@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.
- package/dist/adapters/ai/index.cjs +12 -2
- package/dist/adapters/ai/index.cjs.map +1 -1
- package/dist/adapters/ai/index.js +12 -2
- package/dist/adapters/ai/index.js.map +1 -1
- package/dist/adapters/cloudflare/index.cjs +13 -0
- package/dist/adapters/cloudflare/index.cjs.map +1 -1
- package/dist/adapters/cloudflare/index.js +13 -0
- package/dist/adapters/cloudflare/index.js.map +1 -1
- package/dist/adapters/cloudflare/react.cjs +12 -2
- package/dist/adapters/cloudflare/react.cjs.map +1 -1
- package/dist/adapters/cloudflare/react.js +12 -2
- package/dist/adapters/cloudflare/react.js.map +1 -1
- package/dist/adapters/react/index.cjs +12 -2
- package/dist/adapters/react/index.cjs.map +1 -1
- package/dist/adapters/react/index.js +12 -2
- package/dist/adapters/react/index.js.map +1 -1
- package/dist/client/index.cjs +89 -68
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +2 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +90 -70
- package/dist/client/index.js.map +1 -1
- package/dist/errors.cjs +78 -0
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +7 -1
- package/dist/errors.d.ts +7 -1
- package/dist/errors.js +78 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.cjs +124 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +125 -87
- package/dist/index.js.map +1 -1
- package/dist/{kontext-CgIBANFo.d.cts → kontext-CBPuE-hq.d.cts} +3 -0
- package/dist/{kontext-CgIBANFo.d.ts → kontext-CBPuE-hq.d.ts} +3 -0
- package/dist/management/index.cjs +15 -0
- package/dist/management/index.cjs.map +1 -1
- package/dist/management/index.d.cts +2 -2
- package/dist/management/index.d.ts +2 -2
- package/dist/management/index.js +15 -1
- package/dist/management/index.js.map +1 -1
- package/dist/mcp/index.cjs +13 -2
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.d.cts +3 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.js +14 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/oauth/index.cjs +12 -2
- package/dist/oauth/index.cjs.map +1 -1
- package/dist/oauth/index.d.cts +1 -1
- package/dist/oauth/index.d.ts +1 -1
- package/dist/oauth/index.js +12 -2
- package/dist/oauth/index.js.map +1 -1
- package/dist/server/index.cjs +47 -20
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +48 -21
- package/dist/server/index.js.map +1 -1
- package/dist/{types-C6ep5fVw.d.cts → types-DicGI7ix.d.cts} +21 -1
- package/dist/{types-C6ep5fVw.d.ts → types-DicGI7ix.d.ts} +21 -1
- 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
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
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
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
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
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
3228
|
+
subjectToken,
|
|
3191
3229
|
integrationId,
|
|
3192
3230
|
exchangeConfig
|
|
3193
3231
|
);
|