@kontext-dev/js-sdk 1.0.0 → 1.1.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 (63) hide show
  1. package/dist/adapters/ai/index.cjs +12 -2
  2. package/dist/adapters/ai/index.cjs.map +1 -1
  3. package/dist/adapters/ai/index.js +12 -2
  4. package/dist/adapters/ai/index.js.map +1 -1
  5. package/dist/adapters/cloudflare/index.cjs +13 -0
  6. package/dist/adapters/cloudflare/index.cjs.map +1 -1
  7. package/dist/adapters/cloudflare/index.js +13 -0
  8. package/dist/adapters/cloudflare/index.js.map +1 -1
  9. package/dist/adapters/cloudflare/react.cjs +12 -2
  10. package/dist/adapters/cloudflare/react.cjs.map +1 -1
  11. package/dist/adapters/cloudflare/react.js +12 -2
  12. package/dist/adapters/cloudflare/react.js.map +1 -1
  13. package/dist/adapters/react/index.cjs +12 -2
  14. package/dist/adapters/react/index.cjs.map +1 -1
  15. package/dist/adapters/react/index.js +12 -2
  16. package/dist/adapters/react/index.js.map +1 -1
  17. package/dist/client/index.cjs +89 -68
  18. package/dist/client/index.cjs.map +1 -1
  19. package/dist/client/index.d.cts +2 -0
  20. package/dist/client/index.d.ts +2 -0
  21. package/dist/client/index.js +90 -70
  22. package/dist/client/index.js.map +1 -1
  23. package/dist/errors.cjs +78 -0
  24. package/dist/errors.cjs.map +1 -1
  25. package/dist/errors.d.cts +7 -1
  26. package/dist/errors.d.ts +7 -1
  27. package/dist/errors.js +78 -1
  28. package/dist/errors.js.map +1 -1
  29. package/dist/index.cjs +124 -86
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +1 -1
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.js +125 -87
  34. package/dist/index.js.map +1 -1
  35. package/dist/{kontext-CgIBANFo.d.cts → kontext-CBPuE-hq.d.cts} +3 -0
  36. package/dist/{kontext-CgIBANFo.d.ts → kontext-CBPuE-hq.d.ts} +3 -0
  37. package/dist/management/index.cjs +15 -0
  38. package/dist/management/index.cjs.map +1 -1
  39. package/dist/management/index.d.cts +2 -2
  40. package/dist/management/index.d.ts +2 -2
  41. package/dist/management/index.js +15 -1
  42. package/dist/management/index.js.map +1 -1
  43. package/dist/mcp/index.cjs +13 -2
  44. package/dist/mcp/index.cjs.map +1 -1
  45. package/dist/mcp/index.d.cts +3 -0
  46. package/dist/mcp/index.d.ts +3 -0
  47. package/dist/mcp/index.js +14 -3
  48. package/dist/mcp/index.js.map +1 -1
  49. package/dist/oauth/index.cjs +12 -2
  50. package/dist/oauth/index.cjs.map +1 -1
  51. package/dist/oauth/index.d.cts +1 -1
  52. package/dist/oauth/index.d.ts +1 -1
  53. package/dist/oauth/index.js +12 -2
  54. package/dist/oauth/index.js.map +1 -1
  55. package/dist/server/index.cjs +47 -20
  56. package/dist/server/index.cjs.map +1 -1
  57. package/dist/server/index.d.cts +2 -2
  58. package/dist/server/index.d.ts +2 -2
  59. package/dist/server/index.js +48 -21
  60. package/dist/server/index.js.map +1 -1
  61. package/dist/{types-C6ep5fVw.d.cts → types-DicGI7ix.d.cts} +21 -1
  62. package/dist/{types-C6ep5fVw.d.ts → types-DicGI7ix.d.ts} +21 -1
  63. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -76,8 +76,6 @@ var StorageKeys = {
76
76
  function resourceTokenKey(resource) {
77
77
  return `${StorageKeys.RESOURCE_TOKENS}:${resource}`;
78
78
  }
79
-
80
- // src/errors.ts
81
79
  var KontextError = class extends Error {
82
80
  /** Brand field for type narrowing without instanceof */
83
81
  kontextError = true;
@@ -210,12 +208,20 @@ function isNetworkError(err) {
210
208
  if (typeof causeCode === "string" && NETWORK_ERROR_CODES.has(causeCode))
211
209
  return true;
212
210
  }
211
+ if (err.name === "TypeError") {
212
+ const msg = err.message.toLowerCase();
213
+ if (msg === "failed to fetch" || msg === "load failed" || msg.includes("networkerror")) {
214
+ return true;
215
+ }
216
+ }
213
217
  return false;
214
218
  }
215
219
  function isUnauthorizedError(err) {
216
220
  const props = errorProps(err);
217
221
  if (props.statusCode === 401 || props.status === 401) return true;
222
+ if (props.code === 401) return true;
218
223
  if (err.name === "UnauthorizedError") return true;
224
+ if (err.constructor?.name === "UnauthorizedError") return true;
219
225
  if (err.message === "Unauthorized") return true;
220
226
  return false;
221
227
  }
@@ -274,6 +280,73 @@ function parseHttpError(statusCode, body) {
274
280
  });
275
281
  }
276
282
  }
283
+ var MCP_CODE_MAP = {
284
+ [types_js.ErrorCode.ParseError]: { code: "kontext_mcp_parse_error" },
285
+ [types_js.ErrorCode.InvalidRequest]: { code: "kontext_mcp_invalid_request" },
286
+ [types_js.ErrorCode.MethodNotFound]: { code: "kontext_mcp_method_not_found" },
287
+ [types_js.ErrorCode.InvalidParams]: { code: "kontext_mcp_invalid_params" },
288
+ [types_js.ErrorCode.InternalError]: {
289
+ code: "kontext_mcp_internal_error",
290
+ statusCode: 500
291
+ },
292
+ [types_js.ErrorCode.RequestTimeout]: {
293
+ code: "kontext_mcp_session_expired",
294
+ statusCode: 401
295
+ },
296
+ [types_js.ErrorCode.ConnectionClosed]: { code: "kontext_mcp_session_error" }
297
+ };
298
+ function translateError(err) {
299
+ if (isKontextError(err)) return err;
300
+ if (!(err instanceof Error)) {
301
+ return new KontextError(String(err), "kontext_unknown_error");
302
+ }
303
+ const props = err;
304
+ if (props.code === types_js.ErrorCode.UrlElicitationRequired) {
305
+ const elicitations = props.elicitations ?? props.data?.elicitations;
306
+ const elicitation = elicitations?.[0];
307
+ return new IntegrationConnectionRequiredError(
308
+ elicitation?.integrationId ?? "unknown",
309
+ {
310
+ integrationName: elicitation?.integrationName,
311
+ connectUrl: elicitation?.url,
312
+ message: elicitation?.message,
313
+ cause: err
314
+ }
315
+ );
316
+ }
317
+ if (typeof props.code === "number" && props.code < 0) {
318
+ const entry = MCP_CODE_MAP[props.code];
319
+ if (entry) {
320
+ return new KontextError(err.message, entry.code, {
321
+ statusCode: entry.statusCode,
322
+ cause: err
323
+ });
324
+ }
325
+ return new KontextError(err.message, "kontext_mcp_error", {
326
+ cause: err,
327
+ meta: { mcpCode: props.code }
328
+ });
329
+ }
330
+ const statusCode = props.statusCode ?? props.status ?? (typeof props.code === "number" && props.code >= 400 && props.code < 600 ? props.code : void 0);
331
+ if (typeof statusCode === "number" && statusCode >= 400) {
332
+ if (statusCode === 401) {
333
+ return new AuthorizationRequiredError(err.message, { cause: err });
334
+ }
335
+ return new KontextError(err.message, "kontext_server_error", {
336
+ statusCode,
337
+ cause: err
338
+ });
339
+ }
340
+ if (isUnauthorizedError(err)) {
341
+ return new AuthorizationRequiredError(err.message, { cause: err });
342
+ }
343
+ if (isNetworkError(err)) {
344
+ return new NetworkError(err.message, { cause: err });
345
+ }
346
+ return new KontextError(err.message, "kontext_unknown_error", {
347
+ cause: err
348
+ });
349
+ }
277
350
 
278
351
  // src/oauth/provider.ts
279
352
  var KontextOAuthProvider = class {
@@ -1441,35 +1514,21 @@ async function withTransientRetry(operation, maxRetries = 1) {
1441
1514
  function toKontextError(err, context) {
1442
1515
  const contextMeta = context ? { ...context } : void 0;
1443
1516
  const mergeMeta = (base) => contextMeta ? { ...base ?? {}, ...contextMeta } : base ?? {};
1444
- if (isKontextError(err)) {
1445
- if (!contextMeta) {
1446
- return err;
1447
- }
1448
- const cloned = Object.create(Object.getPrototypeOf(err));
1449
- Object.defineProperties(cloned, Object.getOwnPropertyDescriptors(err));
1450
- Object.defineProperty(cloned, "meta", {
1451
- value: mergeMeta(err.meta),
1452
- enumerable: true,
1453
- writable: true,
1454
- configurable: true
1455
- });
1456
- return cloned;
1517
+ const translated = translateError(err);
1518
+ if (!contextMeta) {
1519
+ return translated;
1457
1520
  }
1458
- if (err instanceof Error) {
1459
- if (isUnauthorizedError(err)) {
1460
- return new AuthorizationRequiredError(err.message, {
1461
- meta: mergeMeta(),
1462
- cause: err
1463
- });
1464
- }
1465
- return new KontextError(err.message, "kontext_unknown_error", {
1466
- meta: mergeMeta(),
1467
- cause: err
1468
- });
1469
- }
1470
- return new KontextError(String(err), "kontext_unknown_error", {
1471
- meta: mergeMeta()
1521
+ const cloned = Object.create(
1522
+ Object.getPrototypeOf(translated)
1523
+ );
1524
+ Object.defineProperties(cloned, Object.getOwnPropertyDescriptors(translated));
1525
+ Object.defineProperty(cloned, "meta", {
1526
+ value: mergeMeta(translated.meta),
1527
+ enumerable: true,
1528
+ writable: true,
1529
+ configurable: true
1472
1530
  });
1531
+ return cloned;
1473
1532
  }
1474
1533
  function isAuthorizationRequired(err) {
1475
1534
  if (err instanceof AuthorizationRequiredError) return true;
@@ -2183,45 +2242,6 @@ function extractTextContent(result) {
2183
2242
  }
2184
2243
  return JSON.stringify(result);
2185
2244
  }
2186
- function translateError(err) {
2187
- if (isKontextError(err)) return err;
2188
- if (!(err instanceof Error)) {
2189
- return new KontextError(String(err), "kontext_unknown_error");
2190
- }
2191
- const props = err;
2192
- if (props.code === -32042) {
2193
- const elicitations = props.elicitations ?? props.data?.elicitations;
2194
- const elicitation = elicitations?.[0];
2195
- return new IntegrationConnectionRequiredError(
2196
- elicitation?.integrationId ?? "unknown",
2197
- {
2198
- integrationName: elicitation?.integrationName,
2199
- connectUrl: elicitation?.url,
2200
- message: elicitation?.message,
2201
- cause: err
2202
- }
2203
- );
2204
- }
2205
- const statusCode = props.statusCode ?? props.status;
2206
- if (typeof statusCode === "number" && statusCode >= 400) {
2207
- if (statusCode === 401) {
2208
- return new AuthorizationRequiredError(err.message, { cause: err });
2209
- }
2210
- return new KontextError(err.message, "kontext_server_error", {
2211
- statusCode,
2212
- cause: err
2213
- });
2214
- }
2215
- if (isUnauthorizedError(err)) {
2216
- return new AuthorizationRequiredError(err.message, { cause: err });
2217
- }
2218
- if (isNetworkError(err)) {
2219
- return new NetworkError(err.message, { cause: err });
2220
- }
2221
- return new KontextError(err.message, "kontext_unknown_error", {
2222
- cause: err
2223
- });
2224
- }
2225
2245
  function createSingleEndpointKontextClient(config) {
2226
2246
  if (!config.clientId) {
2227
2247
  throw new ConfigError(
@@ -2511,6 +2531,7 @@ function createKontextClient(config) {
2511
2531
  // src/management/types.ts
2512
2532
  var TOKEN_EXCHANGE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
2513
2533
  var TOKEN_TYPE_ACCESS_TOKEN = "urn:ietf:params:oauth:token-type:access_token";
2534
+ var TOKEN_TYPE_USER_ID = "urn:kontext:user-id";
2514
2535
 
2515
2536
  // src/oauth/token-exchange.ts
2516
2537
  async function exchangeToken(config, subjectToken, resource, scope, subjectTokenType = TOKEN_TYPE_ACCESS_TOKEN) {
@@ -2990,7 +3011,7 @@ var Kontext = class _Kontext {
2990
3011
  oauthMetadata = null;
2991
3012
  metadataFetchedAt = 0;
2992
3013
  metadataPromise = null;
2993
- // Token exchange caching: keyed by `${integration}\0${subjectToken}`
3014
+ // Token exchange caching: keyed by `${mode}\0${integration}\0${subjectToken}`
2994
3015
  credentialCache = /* @__PURE__ */ new Map();
2995
3016
  resolvedCredentialCache = /* @__PURE__ */ new Map();
2996
3017
  runtimeAuthCache = /* @__PURE__ */ new Map();
@@ -3148,23 +3169,28 @@ var Kontext = class _Kontext {
3148
3169
  router.delete(mcpPath, mcpHandler.delete);
3149
3170
  return router;
3150
3171
  }
3151
- // ===========================================================================
3152
- // require()
3153
- // ===========================================================================
3154
- /**
3155
- * Exchange a user's access token for an integration credential.
3156
- *
3157
- * @param integration - Integration name (e.g., "github")
3158
- * @param token - The user's Bearer token (from `authInfo.token`)
3159
- * @returns Integration credential with `accessToken` and `authorization` header
3160
- *
3161
- * @throws {IntegrationConnectionRequiredError} User hasn't connected this integration
3162
- * @throws {OAuthError} Token exchange failed
3163
- */
3164
- async require(integration, token) {
3172
+ async require(integration, tokenOrOpts) {
3173
+ let isUserIdMode = false;
3174
+ let subjectToken = "";
3175
+ if (typeof tokenOrOpts === "string") {
3176
+ subjectToken = tokenOrOpts;
3177
+ } else if (tokenOrOpts !== null && typeof tokenOrOpts === "object" && typeof tokenOrOpts.userId === "string") {
3178
+ isUserIdMode = true;
3179
+ subjectToken = tokenOrOpts.userId.trim();
3180
+ if (!subjectToken) {
3181
+ throw new TypeError(
3182
+ "Kontext.require() expects a non-empty userId when called with { userId }."
3183
+ );
3184
+ }
3185
+ } else {
3186
+ throw new TypeError(
3187
+ "Kontext.require() expects a token string or { userId: string }."
3188
+ );
3189
+ }
3190
+ const subjectTokenType = isUserIdMode ? TOKEN_TYPE_USER_ID : void 0;
3165
3191
  const now = Date.now();
3166
3192
  this.evictExpiredCredentials(now);
3167
- const cacheKey = `${integration}\0${token}`;
3193
+ const cacheKey = isUserIdMode ? `u\0${integration}\0${subjectToken}` : `t\0${integration}\0${subjectToken}`;
3168
3194
  const cached = this.credentialCache.get(cacheKey);
3169
3195
  if (cached && now < cached.expiresAt) {
3170
3196
  this.credentialCache.delete(cacheKey);
@@ -3181,13 +3207,25 @@ var Kontext = class _Kontext {
3181
3207
  };
3182
3208
  let response;
3183
3209
  try {
3184
- response = await exchangeToken(exchangeConfig, token, integration);
3210
+ response = await exchangeToken(
3211
+ exchangeConfig,
3212
+ subjectToken,
3213
+ integration,
3214
+ void 0,
3215
+ subjectTokenType
3216
+ );
3185
3217
  } catch (err) {
3186
3218
  if (err instanceof OAuthError) {
3187
3219
  if (err.errorCode === "integration_required" || err.message.includes("not connected") || err.message.includes("expired") && err.message.includes("reconnect")) {
3188
3220
  const integrationId = err.meta.integrationId || integration;
3221
+ if (isUserIdMode) {
3222
+ throw new IntegrationConnectionRequiredError(integrationId, {
3223
+ integrationName: err.meta.integrationName,
3224
+ message: err.message
3225
+ });
3226
+ }
3189
3227
  const connectUrl = await this.fetchConnectUrl(
3190
- token,
3228
+ subjectToken,
3191
3229
  integrationId,
3192
3230
  exchangeConfig
3193
3231
  );