@typeship-ax/mcp 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/AGENTS.md +15 -11
  2. package/README.md +22 -53
  3. package/api.json +9998 -10118
  4. package/api.md +8983 -9120
  5. package/dist/arguments.d.ts +54 -0
  6. package/dist/arguments.d.ts.map +1 -0
  7. package/dist/arguments.js +265 -0
  8. package/dist/core/http.d.ts +162 -19
  9. package/dist/core/http.d.ts.map +1 -1
  10. package/dist/core/http.js +381 -48
  11. package/dist/core/pagination.d.ts +42 -6
  12. package/dist/core/pagination.d.ts.map +1 -1
  13. package/dist/core/pagination.js +111 -17
  14. package/dist/credential-storage.d.ts +10 -3
  15. package/dist/credential-storage.d.ts.map +1 -1
  16. package/dist/credential-storage.js +15 -6
  17. package/dist/dates.d.ts +1 -1
  18. package/dist/dates.js +1 -1
  19. package/dist/errors.d.ts +20 -84
  20. package/dist/errors.d.ts.map +1 -1
  21. package/dist/errors.js +20 -108
  22. package/dist/fields.d.ts +36 -0
  23. package/dist/fields.d.ts.map +1 -0
  24. package/dist/fields.js +187 -0
  25. package/dist/index.d.ts +28 -18
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +35 -25
  28. package/dist/mcp-authorization.d.ts.map +1 -1
  29. package/dist/mcp-authorization.js +34 -10
  30. package/dist/mcp-protocol.d.ts +108 -44
  31. package/dist/mcp-protocol.d.ts.map +1 -1
  32. package/dist/mcp-protocol.js +780 -484
  33. package/dist/mcp.d.ts.map +1 -1
  34. package/dist/mcp.js +129 -29
  35. package/dist/named-credentials.d.ts +19 -0
  36. package/dist/named-credentials.d.ts.map +1 -1
  37. package/dist/named-credentials.js +81 -1
  38. package/dist/oauth-request.d.ts +7 -1
  39. package/dist/oauth-request.d.ts.map +1 -1
  40. package/dist/oauth-request.js +26 -4
  41. package/dist/oauth-session.d.ts +13 -1
  42. package/dist/oauth-session.d.ts.map +1 -1
  43. package/dist/oauth-session.js +34 -18
  44. package/dist/ops.d.ts +58 -5
  45. package/dist/ops.d.ts.map +1 -1
  46. package/dist/ops.js +110 -41
  47. package/dist/resources/api-keys.d.ts +10 -7
  48. package/dist/resources/api-keys.d.ts.map +1 -1
  49. package/dist/resources/api-keys.js +10 -31
  50. package/dist/resources/deliveries.d.ts +89 -5
  51. package/dist/resources/deliveries.d.ts.map +1 -1
  52. package/dist/resources/deliveries.js +96 -19
  53. package/dist/resources/drafts.d.ts +16 -16
  54. package/dist/resources/drafts.d.ts.map +1 -1
  55. package/dist/resources/drafts.js +12 -65
  56. package/dist/resources/files.d.ts +4 -4
  57. package/dist/resources/files.d.ts.map +1 -1
  58. package/dist/resources/files.js +3 -12
  59. package/dist/resources/generations.d.ts +16 -16
  60. package/dist/resources/generations.d.ts.map +1 -1
  61. package/dist/resources/generations.js +23 -47
  62. package/dist/resources/organization.d.ts +4 -4
  63. package/dist/resources/organization.d.ts.map +1 -1
  64. package/dist/resources/organization.js +3 -10
  65. package/dist/resources/{generate.d.ts → packages.d.ts} +16 -16
  66. package/dist/resources/packages.d.ts.map +1 -0
  67. package/dist/resources/{generate.js → packages.js} +13 -29
  68. package/dist/resources/projects.d.ts +50 -50
  69. package/dist/resources/projects.d.ts.map +1 -1
  70. package/dist/resources/projects.js +60 -116
  71. package/dist/resources/releases.d.ts +22 -17
  72. package/dist/resources/releases.d.ts.map +1 -1
  73. package/dist/resources/releases.js +19 -40
  74. package/dist/resources/spec-revisions.d.ts +16 -7
  75. package/dist/resources/spec-revisions.d.ts.map +1 -1
  76. package/dist/resources/spec-revisions.js +7 -29
  77. package/dist/resources/specs.d.ts +7 -7
  78. package/dist/resources/specs.d.ts.map +1 -1
  79. package/dist/resources/specs.js +6 -34
  80. package/dist/resources/targets.d.ts +49 -49
  81. package/dist/resources/targets.d.ts.map +1 -1
  82. package/dist/resources/targets.js +59 -115
  83. package/dist/schemas.d.ts.map +1 -1
  84. package/dist/schemas.js +78 -76
  85. package/dist/search.d.ts +54 -0
  86. package/dist/search.d.ts.map +1 -0
  87. package/dist/search.js +421 -0
  88. package/dist/type-docs.d.ts +61 -0
  89. package/dist/type-docs.d.ts.map +1 -0
  90. package/dist/type-docs.js +174 -0
  91. package/dist/types.d.ts +499 -339
  92. package/dist/types.d.ts.map +1 -1
  93. package/dist/types.js +18 -18
  94. package/dist/worker.js +2 -2
  95. package/package.json +5 -2
  96. package/server.json +5 -5
  97. package/src/arguments.ts +254 -0
  98. package/src/core/http.ts +457 -58
  99. package/src/core/pagination.ts +129 -18
  100. package/src/credential-storage.ts +16 -6
  101. package/src/dates.ts +1 -1
  102. package/src/errors.ts +46 -115
  103. package/src/fields.ts +167 -0
  104. package/src/index.ts +45 -28
  105. package/src/mcp-authorization.ts +29 -9
  106. package/src/mcp-protocol.ts +808 -435
  107. package/src/mcp.ts +115 -27
  108. package/src/named-credentials.ts +66 -1
  109. package/src/oauth-request.ts +32 -6
  110. package/src/oauth-session.ts +37 -19
  111. package/src/ops.ts +146 -45
  112. package/src/resources/api-keys.ts +34 -48
  113. package/src/resources/deliveries.ts +213 -32
  114. package/src/resources/drafts.ts +62 -109
  115. package/src/resources/files.ts +19 -20
  116. package/src/resources/generations.ts +61 -79
  117. package/src/resources/organization.ts +11 -16
  118. package/src/resources/{generate.ts → packages.ts} +43 -51
  119. package/src/resources/projects.ts +145 -200
  120. package/src/resources/releases.ts +50 -67
  121. package/src/resources/spec-revisions.ts +40 -49
  122. package/src/resources/specs.ts +39 -59
  123. package/src/resources/targets.ts +144 -194
  124. package/src/schemas.ts +78 -76
  125. package/src/search.ts +434 -0
  126. package/src/type-docs.ts +205 -0
  127. package/src/types.ts +538 -357
  128. package/src/worker.ts +2 -2
  129. package/dist/resources/generate.d.ts.map +0 -1
  130. package/dist/resources/publications.d.ts +0 -47
  131. package/dist/resources/publications.d.ts.map +0 -1
  132. package/dist/resources/publications.js +0 -70
  133. package/src/resources/publications.ts +0 -140
package/dist/mcp.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":";AAuBA,OAAO,EAAoC,KAAK,aAAa,EAAmB,MAAM,YAAY,CAAC;AAenG,OAAO,EAA8C,KAAK,6BAA6B,EAAE,KAAK,kCAAkC,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACpL,YAAY,EAAE,6BAA6B,EAAE,kCAAkC,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC9H,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AA6V3D,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,EAAE,6BAA6B,CAAC;IAC9C;kFAC8E;IAC9E,aAAa,CAAC,EAAE,kCAAkC,CAAC;IACnD;;;;iFAI6E;IAC7E,cAAc,CAAC,SAAS,EAAE,YAAY,GAAG,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACjF;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAMjG;AAED;+EAC+E;AAC/E,wBAAsB,UAAU,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAErE"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":";AAuBA,OAAO,EAAoC,KAAK,aAAa,EAAmB,MAAM,YAAY,CAAC;AAenG,OAAO,EAA8C,KAAK,6BAA6B,EAAE,KAAK,kCAAkC,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACpL,YAAY,EAAE,6BAA6B,EAAE,kCAAkC,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC9H,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAoa3D,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,EAAE,6BAA6B,CAAC;IAC9C;kFAC8E;IAC9E,aAAa,CAAC,EAAE,kCAAkC,CAAC;IACnD;;;;iFAI6E;IAC7E,cAAc,CAAC,SAAS,EAAE,YAAY,GAAG,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACjF;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAMjG;AAED;+EAC+E;AAC/E,wBAAsB,UAAU,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAErE"}
package/dist/mcp.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- // typeship — MCP server. Generated by typeship — https://typeship.dev
2
+ // Typeship — MCP server. Generated by Typeship — https://typeship.dev
3
3
  // Speaks MCP 2026-07-28 and accepts the 2025-11-25 initialize handshake.
4
4
  // HTTP is stateless (no sessions); the protocol layer and tool surface
5
- // live in ./mcp-protocol.js, shared with typeship's hosted endpoint. Two
6
- // transports, zero dependencies:
5
+ // live in ./mcp-protocol.js, shared by both transports. Two transports,
6
+ // zero dependencies:
7
7
  // node mcp.js stdio (newline-delimited JSON-RPC 2.0)
8
8
  // createMcpHandler() configured Streamable HTTP handler
9
9
  // Surface switches (flags or environment):
@@ -21,20 +21,20 @@ import { homedir, tmpdir } from "node:os";
21
21
  import { basename, join } from "node:path";
22
22
  import { fileURLToPath } from "node:url";
23
23
  import { TypeshipClient, formatDebugEvent } from "./index.js";
24
- import { asApiResult } from "./core/http.js";
25
- import { GLOBALS, OMITTED_OPS, OPS, buildArgs } from "./ops.js";
26
- import { DEFAULT_MAX_RESULT_CHARS, SUPPORTED_PROTOCOL_VERSIONS, McpAccountLinkRequired, argumentsError, asJsonRpc, binaryOutcome, callSharedTool, checkRequestHeaders, createStdioRpcHandler, dataOutcome, errorOutcome, handleRpc, isRpcOutcome, pageOutcome, parseIncludeList, prepareCall, resolveReferences, serverInstructions, takeCancelled, textError, toolDefinitions, visibleOps, } from "./mcp-protocol.js";
24
+ import { asApiResult, mediaTypeForPath } from "./core/http.js";
25
+ import { GLOBALS, INPUT_TYPES, OMITTED_OPS, OPS, buildArgs } from "./ops.js";
26
+ import { DEFAULT_MAX_RESULT_CHARS, SUPPORTED_PROTOCOL_VERSIONS, McpAccountLinkRequired, argumentsError, asJsonRpc, binaryOutcome, callSharedTool, checkRequestHeaders, createStdioRpcHandler, dataOutcome, errorOutcome, handleRpc, hiddenOperations, isRpcOutcome, pageOutcome, parseIncludeList, prepareCall, resolveReferences, serverInstructions, requiredScopes, takeCancelled, textError, toolDefinitions, unmatchedIncludes, unsupportedAuthOutcome, visibleOps, } from "./mcp-protocol.js";
27
27
  import { fetchDocsText } from "./docs.js";
28
28
  import { assertCredentialDestination, assertStoredIdentity } from "./oauth-session.js";
29
29
  import { createCredentialStore } from "./credential-storage.js";
30
- import { parseNamedCredentials, resolveNamedCredentials, namedCredentialAvailability } from "./named-credentials.js";
30
+ import { parseNamedCredentials, resolveNamedCredentials, namedCredentialAvailability, missingCredentials, parseExtraHeaders, applyExtraHeaders } from "./named-credentials.js";
31
31
  import { resolveProfile, profileFlag, readProfileConfig } from "./auth-profiles.js";
32
32
  import { createMcpAuthorizer, McpAuthorizationError } from "./mcp-authorization.js";
33
33
  export { McpAccountLinkRequired } from "./mcp-protocol.js";
34
34
  const BIN = "typeship";
35
35
  const PKG_NAME = "@typeship-ax/mcp";
36
36
  const SERVER_NAME = "typeship-mcp";
37
- const SERVER_VERSION = "0.21.0";
37
+ const SERVER_VERSION = "0.23.0";
38
38
  /** The MCP client's announced name (clientInfo in request _meta), for the User-Agent. */
39
39
  let MCP_CLIENT_NAME = null;
40
40
  function noteClientInfo(message) {
@@ -49,8 +49,8 @@ const NAMED_SCHEMES = { "apiKey": { "kind": "bearer", "options": ["bearerToken"]
49
49
  const AUTH_SCALARS = [{ "option": "bearerToken", "flag": "token", "env": "TYPESHIP_TOKEN" }];
50
50
  const BASIC = null;
51
51
  const ENVIRONMENTS = {};
52
- const DOCS_URL_DEFAULT = "https://typeship.dev";
53
- const DOCS_INDEX_URL_DEFAULT = null;
52
+ const DOCS_URL_DEFAULT = "https://typeship.dev/docs";
53
+ const DOCS_INDEX_URL_DEFAULT = "https://typeship.dev/llms.txt";
54
54
  /** "meta" collapses per-operation tools into search/read/execute so huge
55
55
  * APIs don't flood agent context with hundreds of tools. */
56
56
  const TOOL_MODE = "meta";
@@ -63,6 +63,10 @@ const IDENTITY_TOOL = null;
63
63
  const ARGV = process.argv.slice(2);
64
64
  const READ_ONLY = ARGV.includes("--read-only") || process.env["TYPESHIP_MCP_READ_ONLY"] === "1" || process.env["TYPESHIP_MCP_READ_ONLY"] === "true";
65
65
  const INCLUDE = parseIncludeList(ARGV.includes("--tools") ? ARGV[ARGV.indexOf("--tools") + 1] : process.env["TYPESHIP_MCP_TOOLS"]);
66
+ /** How the operator set each switch, for errors that name it. */
67
+ const READ_ONLY_SWITCH = ARGV.includes("--read-only") ? "--read-only" : "TYPESHIP_MCP_READ_ONLY";
68
+ const TOOLS_SWITCH = ARGV.includes("--tools") ? "--tools" : "TYPESHIP_MCP_TOOLS";
69
+ const HEADER_ARGS = ARGV.flatMap((arg, index) => arg === "--header" && ARGV[index + 1] !== undefined ? [ARGV[index + 1]] : arg.startsWith("--header=") ? [arg.slice("--header=".length)] : []);
66
70
  const MAX_RESULT_CHARS = Number(process.env["TYPESHIP_MCP_MAX_RESULT_CHARS"]) || DEFAULT_MAX_RESULT_CHARS;
67
71
  /** One sentence on where credentials come from on each transport; goes
68
72
  * into the instructions and into 401 results. */
@@ -87,7 +91,7 @@ function readJson(file) {
87
91
  }
88
92
  function makeClient(op) {
89
93
  const profile = LOCAL_CREDENTIALS ? resolveProfile(configRoot(), { flag: profileFlag(ARGV), environment: process.env["TYPESHIP_PROFILE"] }) : null;
90
- const store = createCredentialStore(profile?.directory ?? configRoot(), process.env["TYPESHIP_CREDENTIAL_STORE"], "TYPESHIP_CREDENTIAL_STORE");
94
+ const store = createCredentialStore(profile?.directory ?? configRoot(), BIN, process.env["TYPESHIP_CREDENTIAL_STORE"], "TYPESHIP_CREDENTIAL_STORE");
91
95
  if (BASIC && (process.env[BASIC.envUser] !== undefined) !== (process.env[BASIC.envPass] !== undefined))
92
96
  throw new Error("Supply both Basic-auth environment variables together, or use a complete named Basic credential.");
93
97
  const envNamed = LOCAL_CREDENTIALS && process.env["TYPESHIP_CREDENTIALS"] !== undefined ? parseNamedCredentials(process.env["TYPESHIP_CREDENTIALS"], NAMED_SCHEMES) : {};
@@ -136,28 +140,74 @@ function makeClient(op) {
136
140
  { named: stored?.named, options: { ...stored?.scalars, ...(stored?.basic ? { basicAuth: stored.basic } : {}) } },
137
141
  { named: envNamed, options: envOptions },
138
142
  ]);
143
+ requireOperationCredentials(op, options);
139
144
  for (const g of GLOBALS) {
140
145
  const value = process.env["TYPESHIP_" + g.envSuffix];
141
146
  if (value !== undefined)
142
147
  options[g.option] = value;
143
148
  }
144
149
  if (process.env["TYPESHIP_DEBUG"] === "1") {
145
- options.debug = (event) => process.stderr.write(formatDebugEvent(BIN + "-mcp", event) + "\n");
150
+ options.debug = (event) => process.stderr.write(formatDebugEvent(SERVER_NAME, event) + "\n");
146
151
  }
147
152
  // The local MCP server identifies itself (surface + the client it serves, when announced).
148
- options.defaultHeaders = { "User-Agent": PKG_NAME + "-mcp/" + SERVER_VERSION + (MCP_CLIENT_NAME ? " (client=" + MCP_CLIENT_NAME + ")" : "") };
153
+ options.defaultHeaders = { "User-Agent": SERVER_NAME + "/" + SERVER_VERSION + (MCP_CLIENT_NAME ? " (client=" + MCP_CLIENT_NAME + ")" : "") };
154
+ // --header / TYPESHIP_HEADERS: headers the spec does not declare, applied last.
155
+ const extraHeaders = LOCAL_CREDENTIALS ? parseExtraHeaders(process.env["TYPESHIP_HEADERS"], HEADER_ARGS, "TYPESHIP_HEADERS") : {};
156
+ if (Object.keys(extraHeaders).length)
157
+ options.onRequest = (context) => { applyExtraHeaders(context.headers, extraHeaders); };
149
158
  // Keep the SDK's machine-token cache while re-evaluating local configuration.
150
159
  const key = createHash("sha256").update(JSON.stringify([options, config, profile?.name, stored?.oauth?.sessionId, null, process.env["TYPESHIP_DEBUG"]])).digest("hex");
151
160
  if (clientInstance && clientKey === key)
152
161
  return clientInstance;
153
162
  const client = new TypeshipClient(options);
163
+ CLIENT_BASIC.set(client, { basicAuth: options.basicAuth, credentials: options.credentials });
154
164
  clientKey = key;
155
165
  CLIENT_CREDENTIALS.set(client, Object.keys(options.credentials ?? {}).length > 0 || AUTH_SCALARS.some((a) => options[a.option] !== undefined) || options.basicAuth !== undefined || options.bearerToken !== undefined || options.clientCredentials !== undefined);
156
166
  return (clientInstance = client);
157
167
  }
168
+ /** A required operation without one complete credential alternative stops
169
+ * before any request, as the CLI does, with the variables that supply it.
170
+ * Operations with no supported alternative are reported separately. */
171
+ class MissingCredentialsError extends Error {
172
+ outcome;
173
+ constructor(outcome) {
174
+ super("Missing credentials");
175
+ this.outcome = outcome;
176
+ }
177
+ }
178
+ function requireOperationCredentials(op, options) {
179
+ if (op.auth !== "required")
180
+ return;
181
+ const gap = missingCredentials(NAMED_SCHEMES, op.credentialOptions, options);
182
+ if (!gap || !gap.alternatives.length)
183
+ return;
184
+ const names = new Set(gap.missing.flat());
185
+ const needs = (option) => [...names].some((name) => NAMED_SCHEMES[name]?.options.includes(option));
186
+ const scalars = AUTH_SCALARS.filter((scalar) => needs(scalar.option));
187
+ throw new MissingCredentialsError(textError(op.tool + " needs one complete credential alternative. Missing security schemes: " + gap.missing.map((alternative) => alternative.join(" + ")).join(" OR ") + ". No request was sent.", "NO_AUTH", [
188
+ ...scalars.map((scalar) => "Set " + scalar.env + " in the MCP server's environment."),
189
+ ...(BASIC && needs("basicAuth") ? ["Set " + BASIC.envUser + " and " + BASIC.envPass + " in the MCP server's environment."] : []),
190
+ "Or set TYPESHIP_CREDENTIALS to a JSON object with every scheme in one alternative: " + gap.alternatives.map((alternative) => alternative.join(" + ")).join(" OR ") + ".",
191
+ "Credentials saved by '" + BIN + " login' are read on the next call without a restart.",
192
+ ]));
193
+ }
158
194
  let clientInstance;
159
195
  let clientKey = "";
160
196
  const CLIENT_CREDENTIALS = new WeakMap();
197
+ /** Each client's Basic credentials, for path arguments that default to the username. */
198
+ const CLIENT_BASIC = new WeakMap();
199
+ /** The Basic-auth username a path argument of op defaults to (Twilio's
200
+ * AccountSid): the named scheme's, else basicAuth's. */
201
+ function credentialUsername(op, client) {
202
+ const scheme = op.params.find((p) => p.credential)?.credential?.scheme;
203
+ const basic = scheme ? CLIENT_BASIC.get(client) : undefined;
204
+ if (!basic)
205
+ return undefined;
206
+ const named = basic.credentials?.[scheme];
207
+ const username = named && typeof named === "object" ? named.username
208
+ : basic.basicAuth?.username;
209
+ return typeof username === "string" && username !== "" ? username : undefined;
210
+ }
161
211
  /** Resolve configuration and credentials for each tool call, including login/logout changes. */
162
212
  function getClient(op) {
163
213
  return makeClient(op);
@@ -168,10 +218,10 @@ async function callOperationRaw(op, rawArgs, remote, client) {
168
218
  // Arguments are checked against the tool's schema first: unknown names,
169
219
  // wrong types and missing requirements come back as one isError result,
170
220
  // nothing reaches the API half-formed and nothing is dropped silently.
171
- const prepared = prepareCall(op, rawArgs, { maxChars: MAX_RESULT_CHARS });
221
+ const prepared = prepareCall(op, rawArgs, { maxChars: MAX_RESULT_CHARS, credentialUsername: credentialUsername(op, client) });
172
222
  if (!prepared.ok)
173
223
  return prepared.outcome;
174
- const { args, fields, maxChars } = prepared.call;
224
+ const { args, fields, optionalFields, maxChars } = prepared.call;
175
225
  const values = {};
176
226
  for (const p of op.params) {
177
227
  const argument = p.kind === "header" && p.name === "If-Match" ? "if_match" : p.name;
@@ -184,14 +234,21 @@ async function callOperationRaw(op, rawArgs, remote, client) {
184
234
  let rawBody = op.bodyStyle === "data" ? args.body : undefined;
185
235
  if (LOCAL_PROCESS && !remote) {
186
236
  for (const p of op.params) {
187
- if (p.type !== "file" || typeof values[p.name] !== "string")
237
+ if (p.type !== "file")
188
238
  continue;
189
- try {
190
- values[p.name] = fileArgument(values[p.name]);
191
- }
192
- catch (e) {
193
- fileIssues.push({ code: "INVALID_ARGUMENT", argument: p.name, message: p.name + ": cannot read " + String(values[p.name]) + " (" + e.message + ")" });
239
+ const paths = values[p.name];
240
+ if (typeof paths !== "string" && !(Array.isArray(paths) && paths.every((path) => typeof path === "string")))
241
+ continue;
242
+ const files = [];
243
+ for (const path of Array.isArray(paths) ? paths : [paths]) {
244
+ try {
245
+ files.push(fileArgument(path));
246
+ }
247
+ catch (e) {
248
+ fileIssues.push({ code: "INVALID_ARGUMENT", argument: p.name, message: p.name + ": cannot read " + path + " (" + e.message + ")" });
249
+ }
194
250
  }
251
+ values[p.name] = Array.isArray(paths) ? files : files[0];
195
252
  }
196
253
  if (op.bodyKind === "binary" && typeof rawBody === "string") {
197
254
  try {
@@ -204,13 +261,18 @@ async function callOperationRaw(op, rawArgs, remote, client) {
204
261
  }
205
262
  if (fileIssues.length > 0)
206
263
  return argumentsError(op, fileIssues);
264
+ // A tool result is one value: a streamed response is not available here.
265
+ if (op.streamMethod && args[op.streamMethod.flag] === op.streamMethod.value) {
266
+ return argumentsError(op, [{ code: "INVALID_ARGUMENT", argument: op.streamMethod.flag, message: op.streamMethod.flag + ": streaming is not available over MCP, which returns one result per call. Call again without " + op.streamMethod.flag + " " + JSON.stringify(op.streamMethod.value) + " to get the complete response." }]);
267
+ }
207
268
  const callArgs = buildArgs(op, values, rawBody, typeof args.select === "string" ? args.select : undefined);
208
269
  const errorContext = {
209
270
  authHint: remote ? AUTH_HINT_HTTP : AUTH_HINT_STDIO,
210
271
  docsUrl: docsSource.docsUrl(),
211
272
  hadCredential: !!remote || CLIENT_CREDENTIALS.get(client) === true,
273
+ requiredScopes: requiredScopes(op.security),
212
274
  };
213
- const shape = { fields, maxChars, pagination: op.pagination, args };
275
+ const shape = { fields, optionalFields, maxChars, pagination: op.pagination, args, safety: op.safety, outputSchema: op.outputSchema };
214
276
  try {
215
277
  const target = client[op.resource];
216
278
  let result = await asApiResult(target[op.method](...callArgs));
@@ -230,7 +292,7 @@ async function callOperationRaw(op, rawArgs, remote, client) {
230
292
  }
231
293
  if (op.paginated) {
232
294
  const page = result.data;
233
- return pageOutcome(page.items, page.nextPageParams(), { ...shape, requestId: page.response.requestId });
295
+ return pageOutcome(page.items, page.nextPageParams(), { ...shape, requestId: page.response.requestId, carryArgs: op.params.filter((p) => p.required || p.credential).map((p) => p.name) });
234
296
  }
235
297
  // A binary body (the SDK hands back a Blob): an image block, or a file
236
298
  // on disk, never "{}".
@@ -257,9 +319,24 @@ function referenceCacheFor(authHeader) {
257
319
  return cache;
258
320
  }
259
321
  async function callOperation(op, rawArgs, remote) {
260
- const prepared = prepareCall(op, rawArgs, { maxChars: MAX_RESULT_CHARS });
322
+ // A path argument that defaults to the Basic-auth username needs the
323
+ // configured credential before validation; a credential failure is
324
+ // reported below, after the arguments.
325
+ let username;
326
+ if (op.params.some((p) => p.credential && rawArgs[p.name] === undefined)) {
327
+ try {
328
+ username = credentialUsername(op, remote ? await remote.client() : getClient(op));
329
+ }
330
+ catch {
331
+ username = undefined;
332
+ }
333
+ }
334
+ const prepared = prepareCall(op, rawArgs, { maxChars: MAX_RESULT_CHARS, credentialUsername: username });
261
335
  if (!prepared.ok)
262
336
  return prepared.outcome;
337
+ const unsupported = unsupportedAuthOutcome(op);
338
+ if (unsupported)
339
+ return unsupported;
263
340
  // One client/session for the entire tool, including name-to-ID lookups.
264
341
  // If login changes during a lookup, the token callback rejects the old session.
265
342
  let client;
@@ -269,6 +346,8 @@ async function callOperation(op, rawArgs, remote) {
269
346
  catch (error) {
270
347
  if (remote && error instanceof McpAccountLinkRequired)
271
348
  throw error;
349
+ if (!remote && error instanceof MissingCredentialsError)
350
+ return error.outcome;
272
351
  return textError(remote ? "API access is unavailable for this MCP account. Reconnect your API account or contact the server owner." : error.message);
273
352
  }
274
353
  const resolved = await resolveReferences(op, prepared.call.args, {
@@ -281,7 +360,7 @@ async function callOperation(op, rawArgs, remote) {
281
360
  return resolved.outcome;
282
361
  const args = {
283
362
  ...resolved.args,
284
- ...(prepared.call.fields ? { fields: prepared.call.fields.map((path) => path.join(".")) } : {}),
363
+ ...(prepared.call.fields ? { fields: prepared.call.fields.map((path) => (prepared.call.optionalFields.includes(path.join(".")) ? "?" : "") + path.join(".")) } : {}),
285
364
  };
286
365
  return callOperationRaw(op, args, remote, client);
287
366
  }
@@ -306,7 +385,7 @@ const HIDDEN_WRITES = READ_ONLY ? visibleOps(OPS, { include: INCLUDE, uploads: L
306
385
  const HAS_UPLOADS = MCP_OPS.some((op) => op.bodyKind === "multipart" || op.bodyKind === "binary");
307
386
  /** A local file as an upload part (multipart field or raw body). */
308
387
  function fileArgument(path) {
309
- return new File([readFileSync(path)], basename(path));
388
+ return new File([readFileSync(path)], basename(path), { type: mediaTypeForPath(path) });
310
389
  }
311
390
  /** Where binary responses land on a local server: a per-server temp dir. */
312
391
  function saveBinary(bytes, _mediaType, suggestedName) {
@@ -319,6 +398,8 @@ function saveBinary(bytes, _mediaType, suggestedName) {
319
398
  const docsSource = {
320
399
  ops: MCP_OPS,
321
400
  omittedOps: OMITTED_OPS,
401
+ inputTypes: INPUT_TYPES,
402
+ hiddenOps: hiddenOperations(OPS, { readOnly: READ_ONLY, include: INCLUDE, uploads: LOCAL_PROCESS }, { readOnly: READ_ONLY_SWITCH, include: TOOLS_SWITCH }),
322
403
  generatedOperationCount: OPS.length,
323
404
  docsUrl: () => readJson("config.json")?.docsUrl ?? DOCS_URL_DEFAULT,
324
405
  docsIndexUrl: () => readJson("config.json")?.docsUrl ? null : DOCS_INDEX_URL_DEFAULT,
@@ -329,9 +410,9 @@ function serverFor(remote) {
329
410
  const source = remote ? { ...docsSource, ops: operations } : docsSource;
330
411
  const website = docsSource.docsUrl();
331
412
  return {
332
- serverInfo: { name: SERVER_NAME, title: "typeship", version: SERVER_VERSION, ...(website ? { websiteUrl: website } : {}) },
413
+ serverInfo: { name: SERVER_NAME, title: "Typeship", version: SERVER_VERSION, ...(website ? { websiteUrl: website } : {}) },
333
414
  instructions: serverInstructions({
334
- title: "typeship",
415
+ title: "Typeship",
335
416
  ops: operations,
336
417
  toolCount: operations.length,
337
418
  generatedOperationCount: OPS.length,
@@ -451,13 +532,16 @@ async function authorizedHttp(request, authorizer, credentialsFor, apiBaseUrl) {
451
532
  throw new Error("API credentials target a different API URL.");
452
533
  const token = request.headers.get("authorization").slice(7);
453
534
  const transport = credentials.fetch ?? fetch;
454
- return new TypeshipClient({ ...credentials, baseUrl, fetch: async (input, init) => {
535
+ const created = new TypeshipClient({ ...credentials, baseUrl, fetch: async (input, init) => {
455
536
  const headers = new Headers(init?.headers);
456
537
  const destination = new URL(typeof input === "string" ? input : input instanceof URL ? input.href : input.url);
457
538
  if ([...headers.values()].some(value => value === token || value === "Bearer " + token) || [...destination.searchParams.values()].includes(token))
458
539
  throw new Error("An MCP connection token cannot authorize an upstream API request.");
459
540
  return transport(input, init);
460
541
  } });
542
+ const { basicAuth, credentials: named } = credentials;
543
+ CLIENT_BASIC.set(created, { basicAuth, credentials: named });
544
+ return created;
461
545
  })() };
462
546
  let incoming;
463
547
  try {
@@ -571,7 +655,23 @@ function invokedDirectly() {
571
655
  return /mcp\.(js|mjs|ts)$/.test(entry);
572
656
  }
573
657
  }
658
+ /** A --tools value that names nothing would start a server with no
659
+ * operations, which reads to an agent like an empty API. */
660
+ function toolsSwitchProblem() {
661
+ if (ARGV.includes("--tools") && INCLUDE === undefined)
662
+ return "--tools needs a comma-separated list of resources, tool names, or resource.method.";
663
+ const unmatched = unmatchedIncludes(OPS, INCLUDE);
664
+ if (unmatched.length === 0)
665
+ return null;
666
+ const resources = [...new Set(OPS.map((op) => op.resource))];
667
+ return TOOLS_SWITCH + " names nothing in this API: " + unmatched.join(", ") + ". Resources: " + resources.slice(0, 30).join(", ") + (resources.length > 30 ? ", …" : "") + ".";
668
+ }
574
669
  if (invokedDirectly()) {
670
+ const problem = toolsSwitchProblem();
671
+ if (problem !== null) {
672
+ process.stderr.write(SERVER_NAME + ": " + problem + "\n");
673
+ process.exit(2);
674
+ }
575
675
  const httpFlag = process.argv.indexOf("--http");
576
676
  if (httpFlag !== -1) {
577
677
  const port = Number(process.argv[httpFlag + 1]) || Number(process.env.PORT) || 3000;
@@ -16,6 +16,25 @@ export declare function resolveNamedCredentials(schemes: CredentialSchemes, laye
16
16
  }[]): NamedCredentials;
17
17
  /** Make convenience and named inputs comparable without expanding combinations. */
18
18
  export declare function namedCredentialAvailability(schemes: CredentialSchemes, options: Set<string>, named: NamedCredentials): Set<string>;
19
+ /** The schemes an interactive OAuth login session authenticates by name. When
20
+ * the API also declares a separate non-OAuth bearer scheme, the convenience
21
+ * bearer token belongs to that scheme, so the session must be passed to each
22
+ * OAuth scheme by name. Empty: the session is the convenience bearer token. */
23
+ export declare function oauthSessionSchemes(schemes: CredentialSchemes): string[];
24
+ /** Whether resolved client options satisfy one complete credential alternative
25
+ * of an operation. Returns null when satisfied (or when no credential is
26
+ * required); otherwise the named alternatives and the schemes each lacks. */
27
+ export declare function missingCredentials(schemes: CredentialSchemes, credentialOptions: string[][] | undefined, options: Record<string, unknown>): {
28
+ alternatives: string[][];
29
+ missing: string[][];
30
+ } | null;
19
31
  /** Bound file/stdin reads before allocating a full credential document. */
20
32
  export declare function readNamedCredentialsFile(input: string, schemes: CredentialSchemes): NamedCredentials;
33
+ /** Extra request headers from repeated `--header "Name: value"` flags and a
34
+ * `<PREFIX>_HEADERS` variable (a JSON object, or one `Name: value` per line).
35
+ * The escape hatch for credentials a spec does not declare. Flags win over
36
+ * the environment; values never appear in errors. */
37
+ export declare function parseExtraHeaders(environment: string | undefined, flags: readonly string[], variable: string): Record<string, string>;
38
+ /** Apply extra headers last, replacing any header of the same name. */
39
+ export declare function applyExtraHeaders(target: Record<string, string>, extra: Record<string, string>): void;
21
40
  //# sourceMappingURL=named-credentials.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"named-credentials.d.ts","sourceRoot":"","sources":["../src/named-credentials.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9E,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAC/D,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AAEpF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAqBlG;AAED,uFAAuF;AACvF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAAE,GAAG,gBAAgB,CAa/J;AAED,mFAAmF;AACnF,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,gBAAgB,GAAG,GAAG,CAAC,MAAM,CAAC,CAKlI;AAED,2EAA2E;AAC3E,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAkBpG"}
1
+ {"version":3,"file":"named-credentials.d.ts","sourceRoot":"","sources":["../src/named-credentials.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAC1E,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9E,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAC/D,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AAEpF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAqBlG;AAED,uFAAuF;AACvF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAAE,GAAG,gBAAgB,CAa/J;AAED,mFAAmF;AACnF,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,gBAAgB,GAAG,GAAG,CAAC,MAAM,CAAC,CAKlI;AAED;;;+EAG+E;AAC/E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAExE;AAED;;6EAE6E;AAC7E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,YAAY,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAA;CAAE,GAAG,IAAI,CASpM;AAED,2EAA2E;AAC3E,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CAkBpG;AAKD;;;qDAGqD;AACrD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA0BrI;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAKrG"}
@@ -37,7 +37,7 @@ export function resolveNamedCredentials(schemes, layers) {
37
37
  for (const layer of layers) {
38
38
  for (const [name, scheme] of Object.entries(schemes)) {
39
39
  for (const option of scheme.options) {
40
- if (option === "clientCredentials")
40
+ if (option === "clientCredentials" || option === "refreshToken")
41
41
  continue;
42
42
  const value = layer.options?.[option];
43
43
  if (value !== undefined)
@@ -57,6 +57,27 @@ export function namedCredentialAvailability(schemes, options, named) {
57
57
  }
58
58
  return options;
59
59
  }
60
+ /** The schemes an interactive OAuth login session authenticates by name. When
61
+ * the API also declares a separate non-OAuth bearer scheme, the convenience
62
+ * bearer token belongs to that scheme, so the session must be passed to each
63
+ * OAuth scheme by name. Empty: the session is the convenience bearer token. */
64
+ export function oauthSessionSchemes(schemes) {
65
+ return Object.entries(schemes).filter(([, scheme]) => (scheme.options.includes("clientCredentials") || scheme.options.includes("refreshToken")) && !scheme.options.includes("bearerToken")).map(([name]) => name);
66
+ }
67
+ /** Whether resolved client options satisfy one complete credential alternative
68
+ * of an operation. Returns null when satisfied (or when no credential is
69
+ * required); otherwise the named alternatives and the schemes each lacks. */
70
+ export function missingCredentials(schemes, credentialOptions, options) {
71
+ const supplied = (key, value) => typeof value === "function" || (typeof value === "string" && value.length > 0)
72
+ || (key === "clientCredentials" && value !== null && typeof value === "object")
73
+ || (value !== null && typeof value === "object" && "username" in value && "password" in value && typeof value.username === "string" && value.username.length > 0 && typeof value.password === "string" && value.password.length > 0);
74
+ const named = Object.fromEntries(Object.entries((options.credentials ?? {})).filter(([name, value]) => supplied(name, value)));
75
+ const available = namedCredentialAvailability(schemes, new Set(Object.keys(options).filter((key) => key !== "credentials" && supplied(key, options[key]))), named);
76
+ if (credentialOptions?.some((alternative) => alternative.length > 0 && alternative.every((option) => available.has(option))))
77
+ return null;
78
+ const alternatives = (credentialOptions ?? []).filter((alternative) => alternative.length > 0 && alternative.every((option) => option.startsWith("credentials."))).map((alternative) => alternative.map((option) => option.slice("credentials.".length)));
79
+ return { alternatives, missing: alternatives.map((alternative) => alternative.filter((name) => !available.has("credentials." + name))) };
80
+ }
60
81
  /** Bound file/stdin reads before allocating a full credential document. */
61
82
  export function readNamedCredentialsFile(input, schemes) {
62
83
  let fd;
@@ -84,3 +105,62 @@ export function readNamedCredentialsFile(input, schemes) {
84
105
  }
85
106
  return parseNamedCredentials(Buffer.concat(chunks).toString("utf8"), schemes);
86
107
  }
108
+ const HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
109
+ const TRANSPORT_HEADERS = new Set(["host", "content-length", "content-type", "transfer-encoding", "connection"]);
110
+ /** Extra request headers from repeated `--header "Name: value"` flags and a
111
+ * `<PREFIX>_HEADERS` variable (a JSON object, or one `Name: value` per line).
112
+ * The escape hatch for credentials a spec does not declare. Flags win over
113
+ * the environment; values never appear in errors. */
114
+ export function parseExtraHeaders(environment, flags, variable) {
115
+ const entries = [];
116
+ const line = (text, source) => {
117
+ const colon = text.indexOf(":");
118
+ if (colon <= 0)
119
+ throw new Error(source + " expects \"Name: value\".");
120
+ entries.push([text.slice(0, colon).trim(), text.slice(colon + 1).trim()]);
121
+ };
122
+ if (environment !== undefined && environment.trim()) {
123
+ const text = environment.trim();
124
+ if (text.startsWith("{")) {
125
+ let value;
126
+ try {
127
+ value = JSON.parse(text);
128
+ }
129
+ catch {
130
+ throw new Error(variable + " must be a JSON object of header names to values, or one \"Name: value\" per line.");
131
+ }
132
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.values(value).some((entry) => typeof entry !== "string"))
133
+ throw new Error(variable + " must map header names to string values.");
134
+ entries.push(...Object.entries(value));
135
+ }
136
+ else
137
+ for (const part of text.split(/\r?\n/))
138
+ if (part.trim())
139
+ line(part, variable);
140
+ }
141
+ for (const flag of flags)
142
+ line(flag, "--header");
143
+ const headers = {};
144
+ for (const [name, value] of entries) {
145
+ if (!HEADER_NAME.test(name))
146
+ throw new Error("Header names may contain only token characters. Check --header and " + variable + ".");
147
+ if (TRANSPORT_HEADERS.has(name.toLowerCase()))
148
+ throw new Error("The " + name + " header is set by the client and cannot be overridden.");
149
+ if (/[\r\n\0]/.test(value))
150
+ throw new Error("Header values cannot contain line breaks. Check --header and " + variable + ".");
151
+ for (const existing of Object.keys(headers))
152
+ if (existing.toLowerCase() === name.toLowerCase())
153
+ delete headers[existing];
154
+ headers[name] = value;
155
+ }
156
+ return headers;
157
+ }
158
+ /** Apply extra headers last, replacing any header of the same name. */
159
+ export function applyExtraHeaders(target, extra) {
160
+ for (const [name, value] of Object.entries(extra)) {
161
+ for (const existing of Object.keys(target))
162
+ if (existing.toLowerCase() === name.toLowerCase())
163
+ delete target[existing];
164
+ target[name] = value;
165
+ }
166
+ }
@@ -7,8 +7,14 @@ interface AuthenticationResponse {
7
7
  status: number;
8
8
  data?: Record<string, unknown>;
9
9
  error?: DeviceOAuthError;
10
+ /** RFC 6749 `error` and `error_description` from a 400 or 401 body, as
11
+ * "code: description". Only those two fields, printable ASCII, bounded. */
12
+ providerError?: string;
10
13
  }
11
- /** Error bodies and transport causes may contain credentials and are discarded. */
14
+ /** The provider's standard error fields, never any other body content. */
15
+ export declare function providerErrorOf(data: Record<string, unknown>): string | undefined;
16
+ /** Transport causes and error bodies beyond the standard OAuth `error` and
17
+ * `error_description` fields may contain credentials and are discarded. */
12
18
  export declare function oauthJsonRequest(url: string | URL, init?: RequestInit, timeoutMs?: number): Promise<AuthenticationResponse>;
13
19
  /** Device polling needs four protocol errors. Return only their exact names,
14
20
  * never descriptions, error URIs, arbitrary error codes or other body fields. */
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-request.d.ts","sourceRoot":"","sources":["../src/oauth-request.ts"],"names":[],"mappings":"AACA,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,WAAW,GAAG,WAAW,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;gBAC5F,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC;CAY7C;AAED,MAAM,MAAM,gBAAgB,GAAG,uBAAuB,GAAG,WAAW,GAAG,eAAe,GAAG,eAAe,CAAC;AACzG,UAAU,sBAAsB;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,gBAAgB,CAAA;CAAE;AAE7G,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAE/H;AACD;iFACiF;AACjF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAEjI;AACD,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAE7H"}
1
+ {"version":3,"file":"oauth-request.d.ts","sourceRoot":"","sources":["../src/oauth-request.ts"],"names":[],"mappings":"AACA,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,WAAW,GAAG,WAAW,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;gBAC5F,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC;CAY7C;AAED,MAAM,MAAM,gBAAgB,GAAG,uBAAuB,GAAG,WAAW,GAAG,eAAe,GAAG,eAAe,CAAC;AACzG,UAAU,sBAAsB;IAC9B,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzE;+EAC2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAKjF;AAED;2EAC2E;AAC3E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAE/H;AACD;iFACiF;AACjF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAEjI;AACD,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAE7H"}
@@ -13,7 +13,16 @@ export class OAuthResponseError extends Error {
13
13
  this.name = "OAuthResponseError";
14
14
  }
15
15
  }
16
- /** Error bodies and transport causes may contain credentials and are discarded. */
16
+ /** The provider's standard error fields, never any other body content. */
17
+ export function providerErrorOf(data) {
18
+ const code = typeof data.error === "string" && /^[\x20-\x21\x23-\x5b\x5d-\x7e]{1,64}$/.test(data.error) ? data.error : undefined;
19
+ if (!code)
20
+ return undefined;
21
+ const description = typeof data.error_description === "string" ? data.error_description.replace(/[^\x20-\x7e]/g, " ").trim().slice(0, 300) : "";
22
+ return description ? code + ": " + description : code;
23
+ }
24
+ /** Transport causes and error bodies beyond the standard OAuth `error` and
25
+ * `error_description` fields may contain credentials and are discarded. */
17
26
  export function oauthJsonRequest(url, init = {}, timeoutMs = 30_000) {
18
27
  return boundedRequest(url, init, timeoutMs, "json");
19
28
  }
@@ -34,6 +43,9 @@ async function boundedRequest(url, init, timeoutMs, mode) {
34
43
  let reader;
35
44
  let timer;
36
45
  let interrupted;
46
+ // An error status is already an answer: its body only adds the provider's
47
+ // explanation, so a stalled or malformed error body never becomes a failure.
48
+ let errorStatus;
37
49
  let rejectDeadline;
38
50
  const deadline = new Promise((_, reject) => { rejectDeadline = reject; });
39
51
  const stop = (code) => { interrupted ??= code; rejectDeadline(new OAuthResponseError(interrupted)); controller.abort(); };
@@ -56,10 +68,12 @@ async function boundedRequest(url, init, timeoutMs, mode) {
56
68
  void response.body?.cancel().catch(() => { });
57
69
  throw new OAuthResponseError("request_failed");
58
70
  }
59
- if (mode === "status" || response.status !== 200 && !(mode === "device" && response.status === 400)) {
71
+ if (mode === "status" || response.status !== 200 && response.status !== 400 && response.status !== 401) {
60
72
  void response.body?.cancel().catch(() => { });
61
73
  return { status: response.status };
62
74
  }
75
+ if (response.status !== 200)
76
+ errorStatus = response.status;
63
77
  if (!response.body)
64
78
  throw new OAuthResponseError("invalid_response");
65
79
  reader = response.body.getReader();
@@ -90,17 +104,25 @@ async function boundedRequest(url, init, timeoutMs, mode) {
90
104
  data = JSON.parse(text);
91
105
  }
92
106
  catch {
107
+ if (response.status !== 200)
108
+ return { status: response.status };
93
109
  throw new OAuthResponseError("invalid_response");
94
110
  }
95
- if (!data || typeof data !== "object" || Array.isArray(data))
111
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
112
+ if (response.status !== 200)
113
+ return { status: response.status };
96
114
  throw new OAuthResponseError("invalid_response");
115
+ }
97
116
  if (response.status !== 200) {
98
117
  const error = data.error;
99
- return { status: response.status, ...(["authorization_pending", "slow_down", "access_denied", "expired_token"].includes(String(error)) && typeof error === "string" ? { error: error } : {}) };
118
+ const providerError = providerErrorOf(data);
119
+ return { status: response.status, ...(providerError ? { providerError } : {}), ...(mode === "device" && ["authorization_pending", "slow_down", "access_denied", "expired_token"].includes(String(error)) && typeof error === "string" ? { error: error } : {}) };
100
120
  }
101
121
  return { status: response.status, data: data };
102
122
  }
103
123
  catch (error) {
124
+ if (errorStatus !== undefined && interrupted !== "cancelled")
125
+ return { status: errorStatus };
104
126
  if (interrupted)
105
127
  throw new OAuthResponseError(interrupted);
106
128
  if (error instanceof OAuthResponseError)
@@ -70,7 +70,13 @@ export interface CredentialStore {
70
70
  read(): StoredCredentials | null;
71
71
  withLock<T>(work: (store: LockedCredentials) => Promise<T>): Promise<T>;
72
72
  }
73
+ /** The OS credential store or the saved credential file cannot be used. */
73
74
  export declare class CredentialStorageError extends Error {
75
+ constructor(message?: string);
76
+ }
77
+ /** A saved login cannot be used as is; the remedy is to sign in again. */
78
+ export declare class OAuthSessionError extends Error {
79
+ constructor(message?: string);
74
80
  }
75
81
  export interface CredentialCodec {
76
82
  readonly name: string;
@@ -101,6 +107,12 @@ export declare class FileCredentialStore implements CredentialStore {
101
107
  /** Re-read on every request attempt; only one process may rotate the token.
102
108
  * A failed or interrupted exchange requires login, since the server may have
103
109
  * consumed its refresh token even when no response reached this process. */
104
- export declare function oauthSessionToken(store: CredentialStore, config: SessionConfiguration, sessionId: string, tokenParams?: Record<string, string>): Promise<string>;
110
+ export declare function oauthSessionToken(store: CredentialStore, config: SessionConfiguration, sessionId: string, tokenParams?: Record<string, string>, rejected?: string): Promise<string>;
111
+ /** A saved-session token for the request runtime: resolved before every
112
+ * attempt, and after a 401 (invalidate) the next resolve forces one refresh
113
+ * of the token the API rejected. */
114
+ export declare function sessionCredential(resolve: (rejected?: string) => Promise<string>): (() => Promise<string>) & {
115
+ invalidate(): void;
116
+ };
105
117
  export {};
106
118
  //# sourceMappingURL=oauth-session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-session.d.ts","sourceRoot":"","sources":["../src/oauth-session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauth-session.d.ts","sourceRoot":"","sources":["../src/oauth-session.ts"],"names":[],"mappings":"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"}