@kwonye/mcpx 0.1.85 → 0.1.87
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/{cli-p2mah4z3.js → cli-7k3vf6tg.js} +88 -200
- package/dist/{cli-8tdwfb4w.js → cli-t81mwnff.js} +87 -199
- package/dist/cli.js +1 -1
- package/dist/core/index.js +1 -1
- package/dist/gateway/server.d.ts +7 -5
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -2208,7 +2208,7 @@ async function getOAuthAccessToken(serverName, spec, secrets, options = {}) {
|
|
|
2208
2208
|
}
|
|
2209
2209
|
|
|
2210
2210
|
// src/version.ts
|
|
2211
|
-
var APP_VERSION = "0.1.
|
|
2211
|
+
var APP_VERSION = "0.1.87";
|
|
2212
2212
|
|
|
2213
2213
|
// src/core/update.ts
|
|
2214
2214
|
import fs7 from "node:fs";
|
|
@@ -2485,7 +2485,7 @@ import {
|
|
|
2485
2485
|
StdioClientTransport,
|
|
2486
2486
|
getDefaultEnvironment
|
|
2487
2487
|
} from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
2488
|
-
|
|
2488
|
+
import { StreamableHTTPClientTransport, StreamableHTTPError } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
2489
2489
|
var SERVER_VERSION = APP_VERSION;
|
|
2490
2490
|
var DEFAULT_UPSTREAM_TIMEOUT_MS = 60000;
|
|
2491
2491
|
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
@@ -2653,10 +2653,7 @@ function parseNamespacedUri(uri) {
|
|
|
2653
2653
|
};
|
|
2654
2654
|
}
|
|
2655
2655
|
async function callUpstream(upstream, method, params, id, secrets, runtime, passthroughAuthorizationHeader) {
|
|
2656
|
-
|
|
2657
|
-
return callStdioUpstream(upstream, method, params, secrets, runtime);
|
|
2658
|
-
}
|
|
2659
|
-
return callHttpUpstream(upstream, method, params, id, secrets, passthroughAuthorizationHeader);
|
|
2656
|
+
return callUpstreamOnce(upstream, method, params, secrets, runtime, passthroughAuthorizationHeader, false);
|
|
2660
2657
|
}
|
|
2661
2658
|
async function getUpstreamTokenCounts(config, secrets, runtime) {
|
|
2662
2659
|
if (!runtime.tokenCache) {
|
|
@@ -2749,75 +2746,110 @@ function buildStdioServerParameters(spec, secrets) {
|
|
|
2749
2746
|
env: resolveStdioEnv(spec, secrets)
|
|
2750
2747
|
};
|
|
2751
2748
|
}
|
|
2752
|
-
async function
|
|
2749
|
+
async function buildHttpHeaders(upstream, secrets, options) {
|
|
2750
|
+
const headers = {};
|
|
2751
|
+
for (const [key, value] of Object.entries(upstream.spec.headers ?? {})) {
|
|
2752
|
+
if (key.toLowerCase() === "authorization" && isOAuthReference(value)) {
|
|
2753
|
+
const oauthServerName = oauthReferenceServerName(value);
|
|
2754
|
+
const accessToken = await getOAuthAccessToken(oauthServerName, upstream.spec, secrets, {
|
|
2755
|
+
forceRefresh: options.forceOAuthRefresh
|
|
2756
|
+
});
|
|
2757
|
+
headers[key] = `Bearer ${accessToken}`;
|
|
2758
|
+
} else {
|
|
2759
|
+
headers[key] = secrets.resolveMaybeSecret(value);
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
if (options.passthroughAuthorizationHeader) {
|
|
2763
|
+
headers.Authorization = options.passthroughAuthorizationHeader;
|
|
2764
|
+
}
|
|
2765
|
+
return headers;
|
|
2766
|
+
}
|
|
2767
|
+
async function closeUpstreamConnection(entry) {
|
|
2753
2768
|
try {
|
|
2754
2769
|
const connection = await entry.promise;
|
|
2755
2770
|
await connection.transport.close();
|
|
2756
2771
|
} catch {}
|
|
2757
2772
|
}
|
|
2758
|
-
async function
|
|
2773
|
+
async function reconcileUpstreamConnections(config, runtime) {
|
|
2759
2774
|
const activeSpecs = new Map(Object.entries(config.servers).filter(([, spec]) => isServerEnabled(spec)).map(([name, spec]) => [name, specFingerprint(spec)]));
|
|
2760
|
-
const
|
|
2761
|
-
for (const [
|
|
2762
|
-
const
|
|
2775
|
+
const staleKeys = [];
|
|
2776
|
+
for (const [key, entry] of runtime.upstreamConnections.entries()) {
|
|
2777
|
+
const upstreamName = key.includes(":") ? key.slice(0, key.indexOf(":")) : key;
|
|
2778
|
+
const expectedFingerprint = activeSpecs.get(upstreamName);
|
|
2763
2779
|
if (!expectedFingerprint || expectedFingerprint !== entry.fingerprint) {
|
|
2764
|
-
|
|
2780
|
+
staleKeys.push(key);
|
|
2765
2781
|
}
|
|
2766
2782
|
}
|
|
2767
|
-
for (const
|
|
2768
|
-
const entry = runtime.
|
|
2783
|
+
for (const key of staleKeys) {
|
|
2784
|
+
const entry = runtime.upstreamConnections.get(key);
|
|
2769
2785
|
if (!entry) {
|
|
2770
2786
|
continue;
|
|
2771
2787
|
}
|
|
2772
|
-
runtime.
|
|
2773
|
-
await
|
|
2788
|
+
runtime.upstreamConnections.delete(key);
|
|
2789
|
+
await closeUpstreamConnection(entry);
|
|
2774
2790
|
}
|
|
2775
2791
|
}
|
|
2776
|
-
function
|
|
2777
|
-
const
|
|
2792
|
+
function invalidateUpstreamConnection(upstreamName, passthroughAuthorizationHeader, runtime) {
|
|
2793
|
+
const key = passthroughAuthorizationHeader ? `${upstreamName}:passthrough` : upstreamName;
|
|
2794
|
+
const existing = runtime.upstreamConnections.get(key);
|
|
2778
2795
|
if (!existing) {
|
|
2779
2796
|
return;
|
|
2780
2797
|
}
|
|
2781
|
-
runtime.
|
|
2782
|
-
|
|
2798
|
+
runtime.upstreamConnections.delete(key);
|
|
2799
|
+
closeUpstreamConnection(existing);
|
|
2783
2800
|
}
|
|
2784
|
-
async function
|
|
2801
|
+
async function getUpstreamConnection(upstream, secrets, runtime, options = {}) {
|
|
2802
|
+
const { forceOAuthRefresh = false, passthroughAuthorizationHeader } = options;
|
|
2803
|
+
const cacheKey = passthroughAuthorizationHeader ? `${upstream.name}:passthrough` : upstream.name;
|
|
2785
2804
|
const fingerprint = specFingerprint(upstream.spec);
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
if (existing
|
|
2789
|
-
|
|
2805
|
+
if (!forceOAuthRefresh) {
|
|
2806
|
+
const existing = runtime.upstreamConnections.get(cacheKey);
|
|
2807
|
+
if (existing) {
|
|
2808
|
+
if (existing.fingerprint === fingerprint) {
|
|
2809
|
+
return existing.promise;
|
|
2810
|
+
}
|
|
2811
|
+
runtime.upstreamConnections.delete(cacheKey);
|
|
2812
|
+
closeUpstreamConnection(existing);
|
|
2790
2813
|
}
|
|
2791
|
-
runtime.stdioConnections.delete(upstream.name);
|
|
2792
|
-
closeStdioConnection(existing);
|
|
2793
2814
|
}
|
|
2794
2815
|
const promise = (async () => {
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2816
|
+
let transport;
|
|
2817
|
+
if (upstream.spec.transport === "stdio") {
|
|
2818
|
+
transport = new StdioClientTransport(buildStdioServerParameters(upstream.spec, secrets));
|
|
2819
|
+
} else {
|
|
2820
|
+
const headers = await buildHttpHeaders(upstream, secrets, { forceOAuthRefresh, passthroughAuthorizationHeader });
|
|
2821
|
+
const capturingFetch = async (url, init) => {
|
|
2822
|
+
const response = await fetch(url, init);
|
|
2823
|
+
const wwwAuth = response.headers.get("www-authenticate");
|
|
2824
|
+
if (wwwAuth) {
|
|
2825
|
+
if (!runtime.lastWwwAuthenticate) {
|
|
2826
|
+
runtime.lastWwwAuthenticate = new Map;
|
|
2827
|
+
}
|
|
2828
|
+
runtime.lastWwwAuthenticate.set(upstream.name, wwwAuth);
|
|
2829
|
+
}
|
|
2830
|
+
return response;
|
|
2831
|
+
};
|
|
2832
|
+
transport = new StreamableHTTPClientTransport(new URL2(upstream.spec.url), { requestInit: { headers }, fetch: capturingFetch });
|
|
2833
|
+
}
|
|
2834
|
+
const client = new Client({ name: "mcpx", version: SERVER_VERSION });
|
|
2800
2835
|
await withTimeout(client.connect(transport), DEFAULT_CONNECT_TIMEOUT_MS, `Upstream ${upstream.name} failed to connect within ${DEFAULT_CONNECT_TIMEOUT_MS}ms.`);
|
|
2801
|
-
return {
|
|
2802
|
-
fingerprint,
|
|
2803
|
-
client,
|
|
2804
|
-
transport
|
|
2805
|
-
};
|
|
2836
|
+
return { fingerprint, client, transport };
|
|
2806
2837
|
})();
|
|
2807
|
-
runtime.
|
|
2808
|
-
fingerprint,
|
|
2809
|
-
promise
|
|
2810
|
-
});
|
|
2838
|
+
runtime.upstreamConnections.set(cacheKey, { fingerprint, promise });
|
|
2811
2839
|
try {
|
|
2812
2840
|
return await promise;
|
|
2813
2841
|
} catch (error) {
|
|
2814
|
-
runtime.
|
|
2842
|
+
runtime.upstreamConnections.delete(cacheKey);
|
|
2815
2843
|
throw error;
|
|
2816
2844
|
}
|
|
2817
2845
|
}
|
|
2818
|
-
async function
|
|
2846
|
+
async function callUpstreamOnce(upstream, method, params, secrets, runtime, passthroughAuthorizationHeader, forceOAuthRefresh) {
|
|
2847
|
+
const hasOAuth = upstream.spec.transport === "http" && Object.values(upstream.spec.headers ?? {}).some(isOAuthReference);
|
|
2819
2848
|
try {
|
|
2820
|
-
const connection = await
|
|
2849
|
+
const connection = await getUpstreamConnection(upstream, secrets, runtime, {
|
|
2850
|
+
forceOAuthRefresh,
|
|
2851
|
+
passthroughAuthorizationHeader
|
|
2852
|
+
});
|
|
2821
2853
|
const timeoutMs = getConfiguredTimeoutMs();
|
|
2822
2854
|
const timeoutMessage = `Upstream ${upstream.name} timed out after ${timeoutMs}ms for method ${method}.`;
|
|
2823
2855
|
if (method === "tools/list") {
|
|
@@ -2838,161 +2870,17 @@ async function callStdioUpstream(upstream, method, params, secrets, runtime) {
|
|
|
2838
2870
|
if (method === "prompts/get") {
|
|
2839
2871
|
return withTimeout(connection.client.getPrompt(params), timeoutMs, timeoutMessage);
|
|
2840
2872
|
}
|
|
2841
|
-
throw new Error(`Unsupported
|
|
2873
|
+
throw new Error(`Unsupported method: ${method}`);
|
|
2842
2874
|
} catch (error) {
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
}
|
|
2847
|
-
async function callHttpUpstream(upstream, method, params, id, secrets, passthroughAuthorizationHeader) {
|
|
2848
|
-
return callHttpUpstreamOnce(upstream, method, params, id, secrets, passthroughAuthorizationHeader, false);
|
|
2849
|
-
}
|
|
2850
|
-
async function callHttpUpstreamOnce(upstream, method, params, id, secrets, passthroughAuthorizationHeader, forceOAuthRefresh) {
|
|
2851
|
-
const headers = {
|
|
2852
|
-
"content-type": "application/json",
|
|
2853
|
-
accept: "application/json, text/event-stream"
|
|
2854
|
-
};
|
|
2855
|
-
for (const [key, value] of Object.entries(upstream.spec.headers ?? {})) {
|
|
2856
|
-
if (key.toLowerCase() === "authorization" && isOAuthReference(value)) {
|
|
2857
|
-
const oauthServerName = oauthReferenceServerName(value);
|
|
2858
|
-
const accessToken = await getOAuthAccessToken(oauthServerName, upstream.spec, secrets, { forceRefresh: forceOAuthRefresh });
|
|
2859
|
-
headers[key] = `Bearer ${accessToken}`;
|
|
2860
|
-
} else {
|
|
2861
|
-
headers[key] = secrets.resolveMaybeSecret(value);
|
|
2875
|
+
invalidateUpstreamConnection(upstream.name, passthroughAuthorizationHeader, runtime);
|
|
2876
|
+
if (!forceOAuthRefresh && hasOAuth && error instanceof StreamableHTTPError && (error.code === 401 || error.code === 403)) {
|
|
2877
|
+
return callUpstreamOnce(upstream, method, params, secrets, runtime, passthroughAuthorizationHeader, true);
|
|
2862
2878
|
}
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
}
|
|
2867
|
-
const timeoutMs = getConfiguredTimeoutMs();
|
|
2868
|
-
const timeoutController = new AbortController;
|
|
2869
|
-
const timeoutHandle = setTimeout(() => timeoutController.abort(), timeoutMs);
|
|
2870
|
-
let response;
|
|
2871
|
-
try {
|
|
2872
|
-
response = await fetch(upstream.spec.url, {
|
|
2873
|
-
method: "POST",
|
|
2874
|
-
headers,
|
|
2875
|
-
body: JSON.stringify({
|
|
2876
|
-
jsonrpc: JSON_RPC_VERSION2,
|
|
2877
|
-
id,
|
|
2878
|
-
method,
|
|
2879
|
-
params
|
|
2880
|
-
}),
|
|
2881
|
-
signal: timeoutController.signal
|
|
2882
|
-
});
|
|
2883
|
-
} catch (error) {
|
|
2884
|
-
const name = error.name;
|
|
2885
|
-
if (name === "AbortError") {
|
|
2886
|
-
throw new Error(`Upstream ${upstream.name} timed out after ${timeoutMs}ms for method ${method}.`);
|
|
2879
|
+
if (upstream.spec.transport === "http" && error instanceof StreamableHTTPError && error.code) {
|
|
2880
|
+
const wwwAuthenticate = runtime.lastWwwAuthenticate?.get(upstream.name);
|
|
2881
|
+
throw new UpstreamHttpError(upstream.name, error.code, error.message ?? "", wwwAuthenticate);
|
|
2887
2882
|
}
|
|
2888
2883
|
throw error;
|
|
2889
|
-
} finally {
|
|
2890
|
-
clearTimeout(timeoutHandle);
|
|
2891
|
-
}
|
|
2892
|
-
if (!response.ok) {
|
|
2893
|
-
const responseText = await response.text();
|
|
2894
|
-
if (!forceOAuthRefresh && (response.status === 401 || response.status === 403) && Object.values(upstream.spec.headers ?? {}).some((value) => isOAuthReference(value))) {
|
|
2895
|
-
return callHttpUpstreamOnce(upstream, method, params, id, secrets, passthroughAuthorizationHeader, true);
|
|
2896
|
-
}
|
|
2897
|
-
throw new UpstreamHttpError(upstream.name, response.status, responseText, response.headers.get("www-authenticate") ?? undefined);
|
|
2898
|
-
}
|
|
2899
|
-
let payload = null;
|
|
2900
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
2901
|
-
if (contentType.includes("application/json")) {
|
|
2902
|
-
payload = JSON.parse(await response.text());
|
|
2903
|
-
} else if (contentType.includes("text/event-stream")) {
|
|
2904
|
-
payload = await readSseJsonRpcResponse(response, id);
|
|
2905
|
-
} else {
|
|
2906
|
-
try {
|
|
2907
|
-
payload = JSON.parse(await response.text());
|
|
2908
|
-
} catch {
|
|
2909
|
-
payload = null;
|
|
2910
|
-
}
|
|
2911
|
-
}
|
|
2912
|
-
if (!payload) {
|
|
2913
|
-
throw new Error(`Upstream ${upstream.name} response could not be parsed as JSON-RPC payload.`);
|
|
2914
|
-
}
|
|
2915
|
-
if (payload.error) {
|
|
2916
|
-
throw new Error(`Upstream ${upstream.name} error: ${payload.error.message}`);
|
|
2917
|
-
}
|
|
2918
|
-
return payload.result;
|
|
2919
|
-
}
|
|
2920
|
-
async function readSseJsonRpcResponse(response, expectedId) {
|
|
2921
|
-
if (!response.body) {
|
|
2922
|
-
return null;
|
|
2923
|
-
}
|
|
2924
|
-
const decoder = new TextDecoder;
|
|
2925
|
-
const reader = response.body.getReader();
|
|
2926
|
-
let buffer = "";
|
|
2927
|
-
let dataLines = [];
|
|
2928
|
-
let latestPayload = null;
|
|
2929
|
-
const consumeEvent = () => {
|
|
2930
|
-
if (dataLines.length === 0) {
|
|
2931
|
-
return null;
|
|
2932
|
-
}
|
|
2933
|
-
const combined = dataLines.join(`
|
|
2934
|
-
`).trim();
|
|
2935
|
-
dataLines = [];
|
|
2936
|
-
if (!combined || combined === "[DONE]") {
|
|
2937
|
-
return null;
|
|
2938
|
-
}
|
|
2939
|
-
try {
|
|
2940
|
-
const parsed = JSON.parse(combined);
|
|
2941
|
-
latestPayload = parsed;
|
|
2942
|
-
const parsedId = parsed.id ?? null;
|
|
2943
|
-
if (parsedId === expectedId) {
|
|
2944
|
-
return parsed;
|
|
2945
|
-
}
|
|
2946
|
-
return null;
|
|
2947
|
-
} catch {
|
|
2948
|
-
return null;
|
|
2949
|
-
}
|
|
2950
|
-
};
|
|
2951
|
-
try {
|
|
2952
|
-
while (true) {
|
|
2953
|
-
const { value, done } = await reader.read();
|
|
2954
|
-
if (done) {
|
|
2955
|
-
break;
|
|
2956
|
-
}
|
|
2957
|
-
buffer += decoder.decode(value, { stream: true });
|
|
2958
|
-
while (true) {
|
|
2959
|
-
const newlineIndex = buffer.indexOf(`
|
|
2960
|
-
`);
|
|
2961
|
-
if (newlineIndex < 0) {
|
|
2962
|
-
break;
|
|
2963
|
-
}
|
|
2964
|
-
let line = buffer.slice(0, newlineIndex);
|
|
2965
|
-
buffer = buffer.slice(newlineIndex + 1);
|
|
2966
|
-
if (line.endsWith("\r")) {
|
|
2967
|
-
line = line.slice(0, -1);
|
|
2968
|
-
}
|
|
2969
|
-
if (line.startsWith("data:")) {
|
|
2970
|
-
dataLines.push(line.slice("data:".length).trimStart());
|
|
2971
|
-
continue;
|
|
2972
|
-
}
|
|
2973
|
-
if (line === "") {
|
|
2974
|
-
const matched = consumeEvent();
|
|
2975
|
-
if (matched) {
|
|
2976
|
-
return matched;
|
|
2977
|
-
}
|
|
2978
|
-
}
|
|
2979
|
-
}
|
|
2980
|
-
}
|
|
2981
|
-
buffer += decoder.decode();
|
|
2982
|
-
if (buffer.length > 0) {
|
|
2983
|
-
let finalLine = buffer;
|
|
2984
|
-
if (finalLine.endsWith("\r")) {
|
|
2985
|
-
finalLine = finalLine.slice(0, -1);
|
|
2986
|
-
}
|
|
2987
|
-
if (finalLine.startsWith("data:")) {
|
|
2988
|
-
dataLines.push(finalLine.slice("data:".length).trimStart());
|
|
2989
|
-
}
|
|
2990
|
-
}
|
|
2991
|
-
return consumeEvent() ?? latestPayload;
|
|
2992
|
-
} finally {
|
|
2993
|
-
try {
|
|
2994
|
-
await reader.cancel();
|
|
2995
|
-
} catch {}
|
|
2996
2884
|
}
|
|
2997
2885
|
}
|
|
2998
2886
|
function authHeaderIsValid(request, expectedToken) {
|
|
@@ -3255,7 +3143,7 @@ async function handleRequestObject(request, secrets, runtime, upstreamFilter, cl
|
|
|
3255
3143
|
if (upstreamFilter && listUpstreams(config, upstreamFilter).length === 0) {
|
|
3256
3144
|
return makeError(id, -32602, `Unknown upstream: ${upstreamFilter}`);
|
|
3257
3145
|
}
|
|
3258
|
-
await
|
|
3146
|
+
await reconcileUpstreamConnections(config, runtime);
|
|
3259
3147
|
if (request.method === "custom/tokenCounts") {
|
|
3260
3148
|
const result = await getUpstreamTokenCounts(config, secrets, runtime);
|
|
3261
3149
|
return makeResult(id, result);
|
|
@@ -3351,7 +3239,7 @@ async function maybeHandleWellKnownOAuthRequest(request, response, requestUrl, s
|
|
|
3351
3239
|
function createGatewayServer(options) {
|
|
3352
3240
|
const debug = process.env.MCPX_GATEWAY_DEBUG === "1";
|
|
3353
3241
|
const runtime = {
|
|
3354
|
-
|
|
3242
|
+
upstreamConnections: new Map,
|
|
3355
3243
|
upstreamErrors: new Map
|
|
3356
3244
|
};
|
|
3357
3245
|
const server = http2.createServer(async (request, response) => {
|
|
@@ -3517,10 +3405,10 @@ function createGatewayServer(options) {
|
|
|
3517
3405
|
}
|
|
3518
3406
|
});
|
|
3519
3407
|
server.on("close", () => {
|
|
3520
|
-
for (const entry of runtime.
|
|
3521
|
-
|
|
3408
|
+
for (const entry of runtime.upstreamConnections.values()) {
|
|
3409
|
+
closeUpstreamConnection(entry);
|
|
3522
3410
|
}
|
|
3523
|
-
runtime.
|
|
3411
|
+
runtime.upstreamConnections.clear();
|
|
3524
3412
|
});
|
|
3525
3413
|
server.listen(options.port, "127.0.0.1");
|
|
3526
3414
|
return server;
|
|
@@ -2485,7 +2485,7 @@ import {
|
|
|
2485
2485
|
StdioClientTransport,
|
|
2486
2486
|
getDefaultEnvironment
|
|
2487
2487
|
} from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
2488
|
-
|
|
2488
|
+
import { StreamableHTTPClientTransport, StreamableHTTPError } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
2489
2489
|
var SERVER_VERSION = APP_VERSION;
|
|
2490
2490
|
var DEFAULT_UPSTREAM_TIMEOUT_MS = 60000;
|
|
2491
2491
|
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
@@ -2653,10 +2653,7 @@ function parseNamespacedUri(uri) {
|
|
|
2653
2653
|
};
|
|
2654
2654
|
}
|
|
2655
2655
|
async function callUpstream(upstream, method, params, id, secrets, runtime, passthroughAuthorizationHeader) {
|
|
2656
|
-
|
|
2657
|
-
return callStdioUpstream(upstream, method, params, secrets, runtime);
|
|
2658
|
-
}
|
|
2659
|
-
return callHttpUpstream(upstream, method, params, id, secrets, passthroughAuthorizationHeader);
|
|
2656
|
+
return callUpstreamOnce(upstream, method, params, secrets, runtime, passthroughAuthorizationHeader, false);
|
|
2660
2657
|
}
|
|
2661
2658
|
async function getUpstreamTokenCounts(config, secrets, runtime) {
|
|
2662
2659
|
if (!runtime.tokenCache) {
|
|
@@ -2749,75 +2746,110 @@ function buildStdioServerParameters(spec, secrets) {
|
|
|
2749
2746
|
env: resolveStdioEnv(spec, secrets)
|
|
2750
2747
|
};
|
|
2751
2748
|
}
|
|
2752
|
-
async function
|
|
2749
|
+
async function buildHttpHeaders(upstream, secrets, options) {
|
|
2750
|
+
const headers = {};
|
|
2751
|
+
for (const [key, value] of Object.entries(upstream.spec.headers ?? {})) {
|
|
2752
|
+
if (key.toLowerCase() === "authorization" && isOAuthReference(value)) {
|
|
2753
|
+
const oauthServerName = oauthReferenceServerName(value);
|
|
2754
|
+
const accessToken = await getOAuthAccessToken(oauthServerName, upstream.spec, secrets, {
|
|
2755
|
+
forceRefresh: options.forceOAuthRefresh
|
|
2756
|
+
});
|
|
2757
|
+
headers[key] = `Bearer ${accessToken}`;
|
|
2758
|
+
} else {
|
|
2759
|
+
headers[key] = secrets.resolveMaybeSecret(value);
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
if (options.passthroughAuthorizationHeader) {
|
|
2763
|
+
headers.Authorization = options.passthroughAuthorizationHeader;
|
|
2764
|
+
}
|
|
2765
|
+
return headers;
|
|
2766
|
+
}
|
|
2767
|
+
async function closeUpstreamConnection(entry) {
|
|
2753
2768
|
try {
|
|
2754
2769
|
const connection = await entry.promise;
|
|
2755
2770
|
await connection.transport.close();
|
|
2756
2771
|
} catch {}
|
|
2757
2772
|
}
|
|
2758
|
-
async function
|
|
2773
|
+
async function reconcileUpstreamConnections(config, runtime) {
|
|
2759
2774
|
const activeSpecs = new Map(Object.entries(config.servers).filter(([, spec]) => isServerEnabled(spec)).map(([name, spec]) => [name, specFingerprint(spec)]));
|
|
2760
|
-
const
|
|
2761
|
-
for (const [
|
|
2762
|
-
const
|
|
2775
|
+
const staleKeys = [];
|
|
2776
|
+
for (const [key, entry] of runtime.upstreamConnections.entries()) {
|
|
2777
|
+
const upstreamName = key.includes(":") ? key.slice(0, key.indexOf(":")) : key;
|
|
2778
|
+
const expectedFingerprint = activeSpecs.get(upstreamName);
|
|
2763
2779
|
if (!expectedFingerprint || expectedFingerprint !== entry.fingerprint) {
|
|
2764
|
-
|
|
2780
|
+
staleKeys.push(key);
|
|
2765
2781
|
}
|
|
2766
2782
|
}
|
|
2767
|
-
for (const
|
|
2768
|
-
const entry = runtime.
|
|
2783
|
+
for (const key of staleKeys) {
|
|
2784
|
+
const entry = runtime.upstreamConnections.get(key);
|
|
2769
2785
|
if (!entry) {
|
|
2770
2786
|
continue;
|
|
2771
2787
|
}
|
|
2772
|
-
runtime.
|
|
2773
|
-
await
|
|
2788
|
+
runtime.upstreamConnections.delete(key);
|
|
2789
|
+
await closeUpstreamConnection(entry);
|
|
2774
2790
|
}
|
|
2775
2791
|
}
|
|
2776
|
-
function
|
|
2777
|
-
const
|
|
2792
|
+
function invalidateUpstreamConnection(upstreamName, passthroughAuthorizationHeader, runtime) {
|
|
2793
|
+
const key = passthroughAuthorizationHeader ? `${upstreamName}:passthrough` : upstreamName;
|
|
2794
|
+
const existing = runtime.upstreamConnections.get(key);
|
|
2778
2795
|
if (!existing) {
|
|
2779
2796
|
return;
|
|
2780
2797
|
}
|
|
2781
|
-
runtime.
|
|
2782
|
-
|
|
2798
|
+
runtime.upstreamConnections.delete(key);
|
|
2799
|
+
closeUpstreamConnection(existing);
|
|
2783
2800
|
}
|
|
2784
|
-
async function
|
|
2801
|
+
async function getUpstreamConnection(upstream, secrets, runtime, options = {}) {
|
|
2802
|
+
const { forceOAuthRefresh = false, passthroughAuthorizationHeader } = options;
|
|
2803
|
+
const cacheKey = passthroughAuthorizationHeader ? `${upstream.name}:passthrough` : upstream.name;
|
|
2785
2804
|
const fingerprint = specFingerprint(upstream.spec);
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
if (existing
|
|
2789
|
-
|
|
2805
|
+
if (!forceOAuthRefresh) {
|
|
2806
|
+
const existing = runtime.upstreamConnections.get(cacheKey);
|
|
2807
|
+
if (existing) {
|
|
2808
|
+
if (existing.fingerprint === fingerprint) {
|
|
2809
|
+
return existing.promise;
|
|
2810
|
+
}
|
|
2811
|
+
runtime.upstreamConnections.delete(cacheKey);
|
|
2812
|
+
closeUpstreamConnection(existing);
|
|
2790
2813
|
}
|
|
2791
|
-
runtime.stdioConnections.delete(upstream.name);
|
|
2792
|
-
closeStdioConnection(existing);
|
|
2793
2814
|
}
|
|
2794
2815
|
const promise = (async () => {
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2816
|
+
let transport;
|
|
2817
|
+
if (upstream.spec.transport === "stdio") {
|
|
2818
|
+
transport = new StdioClientTransport(buildStdioServerParameters(upstream.spec, secrets));
|
|
2819
|
+
} else {
|
|
2820
|
+
const headers = await buildHttpHeaders(upstream, secrets, { forceOAuthRefresh, passthroughAuthorizationHeader });
|
|
2821
|
+
const capturingFetch = async (url, init) => {
|
|
2822
|
+
const response = await fetch(url, init);
|
|
2823
|
+
const wwwAuth = response.headers.get("www-authenticate");
|
|
2824
|
+
if (wwwAuth) {
|
|
2825
|
+
if (!runtime.lastWwwAuthenticate) {
|
|
2826
|
+
runtime.lastWwwAuthenticate = new Map;
|
|
2827
|
+
}
|
|
2828
|
+
runtime.lastWwwAuthenticate.set(upstream.name, wwwAuth);
|
|
2829
|
+
}
|
|
2830
|
+
return response;
|
|
2831
|
+
};
|
|
2832
|
+
transport = new StreamableHTTPClientTransport(new URL2(upstream.spec.url), { requestInit: { headers }, fetch: capturingFetch });
|
|
2833
|
+
}
|
|
2834
|
+
const client = new Client({ name: "mcpx", version: SERVER_VERSION });
|
|
2800
2835
|
await withTimeout(client.connect(transport), DEFAULT_CONNECT_TIMEOUT_MS, `Upstream ${upstream.name} failed to connect within ${DEFAULT_CONNECT_TIMEOUT_MS}ms.`);
|
|
2801
|
-
return {
|
|
2802
|
-
fingerprint,
|
|
2803
|
-
client,
|
|
2804
|
-
transport
|
|
2805
|
-
};
|
|
2836
|
+
return { fingerprint, client, transport };
|
|
2806
2837
|
})();
|
|
2807
|
-
runtime.
|
|
2808
|
-
fingerprint,
|
|
2809
|
-
promise
|
|
2810
|
-
});
|
|
2838
|
+
runtime.upstreamConnections.set(cacheKey, { fingerprint, promise });
|
|
2811
2839
|
try {
|
|
2812
2840
|
return await promise;
|
|
2813
2841
|
} catch (error) {
|
|
2814
|
-
runtime.
|
|
2842
|
+
runtime.upstreamConnections.delete(cacheKey);
|
|
2815
2843
|
throw error;
|
|
2816
2844
|
}
|
|
2817
2845
|
}
|
|
2818
|
-
async function
|
|
2846
|
+
async function callUpstreamOnce(upstream, method, params, secrets, runtime, passthroughAuthorizationHeader, forceOAuthRefresh) {
|
|
2847
|
+
const hasOAuth = upstream.spec.transport === "http" && Object.values(upstream.spec.headers ?? {}).some(isOAuthReference);
|
|
2819
2848
|
try {
|
|
2820
|
-
const connection = await
|
|
2849
|
+
const connection = await getUpstreamConnection(upstream, secrets, runtime, {
|
|
2850
|
+
forceOAuthRefresh,
|
|
2851
|
+
passthroughAuthorizationHeader
|
|
2852
|
+
});
|
|
2821
2853
|
const timeoutMs = getConfiguredTimeoutMs();
|
|
2822
2854
|
const timeoutMessage = `Upstream ${upstream.name} timed out after ${timeoutMs}ms for method ${method}.`;
|
|
2823
2855
|
if (method === "tools/list") {
|
|
@@ -2838,161 +2870,17 @@ async function callStdioUpstream(upstream, method, params, secrets, runtime) {
|
|
|
2838
2870
|
if (method === "prompts/get") {
|
|
2839
2871
|
return withTimeout(connection.client.getPrompt(params), timeoutMs, timeoutMessage);
|
|
2840
2872
|
}
|
|
2841
|
-
throw new Error(`Unsupported
|
|
2873
|
+
throw new Error(`Unsupported method: ${method}`);
|
|
2842
2874
|
} catch (error) {
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
}
|
|
2847
|
-
async function callHttpUpstream(upstream, method, params, id, secrets, passthroughAuthorizationHeader) {
|
|
2848
|
-
return callHttpUpstreamOnce(upstream, method, params, id, secrets, passthroughAuthorizationHeader, false);
|
|
2849
|
-
}
|
|
2850
|
-
async function callHttpUpstreamOnce(upstream, method, params, id, secrets, passthroughAuthorizationHeader, forceOAuthRefresh) {
|
|
2851
|
-
const headers = {
|
|
2852
|
-
"content-type": "application/json",
|
|
2853
|
-
accept: "application/json, text/event-stream"
|
|
2854
|
-
};
|
|
2855
|
-
for (const [key, value] of Object.entries(upstream.spec.headers ?? {})) {
|
|
2856
|
-
if (key.toLowerCase() === "authorization" && isOAuthReference(value)) {
|
|
2857
|
-
const oauthServerName = oauthReferenceServerName(value);
|
|
2858
|
-
const accessToken = await getOAuthAccessToken(oauthServerName, upstream.spec, secrets, { forceRefresh: forceOAuthRefresh });
|
|
2859
|
-
headers[key] = `Bearer ${accessToken}`;
|
|
2860
|
-
} else {
|
|
2861
|
-
headers[key] = secrets.resolveMaybeSecret(value);
|
|
2875
|
+
invalidateUpstreamConnection(upstream.name, passthroughAuthorizationHeader, runtime);
|
|
2876
|
+
if (!forceOAuthRefresh && hasOAuth && error instanceof StreamableHTTPError && (error.code === 401 || error.code === 403)) {
|
|
2877
|
+
return callUpstreamOnce(upstream, method, params, secrets, runtime, passthroughAuthorizationHeader, true);
|
|
2862
2878
|
}
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
}
|
|
2867
|
-
const timeoutMs = getConfiguredTimeoutMs();
|
|
2868
|
-
const timeoutController = new AbortController;
|
|
2869
|
-
const timeoutHandle = setTimeout(() => timeoutController.abort(), timeoutMs);
|
|
2870
|
-
let response;
|
|
2871
|
-
try {
|
|
2872
|
-
response = await fetch(upstream.spec.url, {
|
|
2873
|
-
method: "POST",
|
|
2874
|
-
headers,
|
|
2875
|
-
body: JSON.stringify({
|
|
2876
|
-
jsonrpc: JSON_RPC_VERSION2,
|
|
2877
|
-
id,
|
|
2878
|
-
method,
|
|
2879
|
-
params
|
|
2880
|
-
}),
|
|
2881
|
-
signal: timeoutController.signal
|
|
2882
|
-
});
|
|
2883
|
-
} catch (error) {
|
|
2884
|
-
const name = error.name;
|
|
2885
|
-
if (name === "AbortError") {
|
|
2886
|
-
throw new Error(`Upstream ${upstream.name} timed out after ${timeoutMs}ms for method ${method}.`);
|
|
2879
|
+
if (upstream.spec.transport === "http" && error instanceof StreamableHTTPError && error.code) {
|
|
2880
|
+
const wwwAuthenticate = runtime.lastWwwAuthenticate?.get(upstream.name);
|
|
2881
|
+
throw new UpstreamHttpError(upstream.name, error.code, error.message ?? "", wwwAuthenticate);
|
|
2887
2882
|
}
|
|
2888
2883
|
throw error;
|
|
2889
|
-
} finally {
|
|
2890
|
-
clearTimeout(timeoutHandle);
|
|
2891
|
-
}
|
|
2892
|
-
if (!response.ok) {
|
|
2893
|
-
const responseText = await response.text();
|
|
2894
|
-
if (!forceOAuthRefresh && (response.status === 401 || response.status === 403) && Object.values(upstream.spec.headers ?? {}).some((value) => isOAuthReference(value))) {
|
|
2895
|
-
return callHttpUpstreamOnce(upstream, method, params, id, secrets, passthroughAuthorizationHeader, true);
|
|
2896
|
-
}
|
|
2897
|
-
throw new UpstreamHttpError(upstream.name, response.status, responseText, response.headers.get("www-authenticate") ?? undefined);
|
|
2898
|
-
}
|
|
2899
|
-
let payload = null;
|
|
2900
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
2901
|
-
if (contentType.includes("application/json")) {
|
|
2902
|
-
payload = JSON.parse(await response.text());
|
|
2903
|
-
} else if (contentType.includes("text/event-stream")) {
|
|
2904
|
-
payload = await readSseJsonRpcResponse(response, id);
|
|
2905
|
-
} else {
|
|
2906
|
-
try {
|
|
2907
|
-
payload = JSON.parse(await response.text());
|
|
2908
|
-
} catch {
|
|
2909
|
-
payload = null;
|
|
2910
|
-
}
|
|
2911
|
-
}
|
|
2912
|
-
if (!payload) {
|
|
2913
|
-
throw new Error(`Upstream ${upstream.name} response could not be parsed as JSON-RPC payload.`);
|
|
2914
|
-
}
|
|
2915
|
-
if (payload.error) {
|
|
2916
|
-
throw new Error(`Upstream ${upstream.name} error: ${payload.error.message}`);
|
|
2917
|
-
}
|
|
2918
|
-
return payload.result;
|
|
2919
|
-
}
|
|
2920
|
-
async function readSseJsonRpcResponse(response, expectedId) {
|
|
2921
|
-
if (!response.body) {
|
|
2922
|
-
return null;
|
|
2923
|
-
}
|
|
2924
|
-
const decoder = new TextDecoder;
|
|
2925
|
-
const reader = response.body.getReader();
|
|
2926
|
-
let buffer = "";
|
|
2927
|
-
let dataLines = [];
|
|
2928
|
-
let latestPayload = null;
|
|
2929
|
-
const consumeEvent = () => {
|
|
2930
|
-
if (dataLines.length === 0) {
|
|
2931
|
-
return null;
|
|
2932
|
-
}
|
|
2933
|
-
const combined = dataLines.join(`
|
|
2934
|
-
`).trim();
|
|
2935
|
-
dataLines = [];
|
|
2936
|
-
if (!combined || combined === "[DONE]") {
|
|
2937
|
-
return null;
|
|
2938
|
-
}
|
|
2939
|
-
try {
|
|
2940
|
-
const parsed = JSON.parse(combined);
|
|
2941
|
-
latestPayload = parsed;
|
|
2942
|
-
const parsedId = parsed.id ?? null;
|
|
2943
|
-
if (parsedId === expectedId) {
|
|
2944
|
-
return parsed;
|
|
2945
|
-
}
|
|
2946
|
-
return null;
|
|
2947
|
-
} catch {
|
|
2948
|
-
return null;
|
|
2949
|
-
}
|
|
2950
|
-
};
|
|
2951
|
-
try {
|
|
2952
|
-
while (true) {
|
|
2953
|
-
const { value, done } = await reader.read();
|
|
2954
|
-
if (done) {
|
|
2955
|
-
break;
|
|
2956
|
-
}
|
|
2957
|
-
buffer += decoder.decode(value, { stream: true });
|
|
2958
|
-
while (true) {
|
|
2959
|
-
const newlineIndex = buffer.indexOf(`
|
|
2960
|
-
`);
|
|
2961
|
-
if (newlineIndex < 0) {
|
|
2962
|
-
break;
|
|
2963
|
-
}
|
|
2964
|
-
let line = buffer.slice(0, newlineIndex);
|
|
2965
|
-
buffer = buffer.slice(newlineIndex + 1);
|
|
2966
|
-
if (line.endsWith("\r")) {
|
|
2967
|
-
line = line.slice(0, -1);
|
|
2968
|
-
}
|
|
2969
|
-
if (line.startsWith("data:")) {
|
|
2970
|
-
dataLines.push(line.slice("data:".length).trimStart());
|
|
2971
|
-
continue;
|
|
2972
|
-
}
|
|
2973
|
-
if (line === "") {
|
|
2974
|
-
const matched = consumeEvent();
|
|
2975
|
-
if (matched) {
|
|
2976
|
-
return matched;
|
|
2977
|
-
}
|
|
2978
|
-
}
|
|
2979
|
-
}
|
|
2980
|
-
}
|
|
2981
|
-
buffer += decoder.decode();
|
|
2982
|
-
if (buffer.length > 0) {
|
|
2983
|
-
let finalLine = buffer;
|
|
2984
|
-
if (finalLine.endsWith("\r")) {
|
|
2985
|
-
finalLine = finalLine.slice(0, -1);
|
|
2986
|
-
}
|
|
2987
|
-
if (finalLine.startsWith("data:")) {
|
|
2988
|
-
dataLines.push(finalLine.slice("data:".length).trimStart());
|
|
2989
|
-
}
|
|
2990
|
-
}
|
|
2991
|
-
return consumeEvent() ?? latestPayload;
|
|
2992
|
-
} finally {
|
|
2993
|
-
try {
|
|
2994
|
-
await reader.cancel();
|
|
2995
|
-
} catch {}
|
|
2996
2884
|
}
|
|
2997
2885
|
}
|
|
2998
2886
|
function authHeaderIsValid(request, expectedToken) {
|
|
@@ -3255,7 +3143,7 @@ async function handleRequestObject(request, secrets, runtime, upstreamFilter, cl
|
|
|
3255
3143
|
if (upstreamFilter && listUpstreams(config, upstreamFilter).length === 0) {
|
|
3256
3144
|
return makeError(id, -32602, `Unknown upstream: ${upstreamFilter}`);
|
|
3257
3145
|
}
|
|
3258
|
-
await
|
|
3146
|
+
await reconcileUpstreamConnections(config, runtime);
|
|
3259
3147
|
if (request.method === "custom/tokenCounts") {
|
|
3260
3148
|
const result = await getUpstreamTokenCounts(config, secrets, runtime);
|
|
3261
3149
|
return makeResult(id, result);
|
|
@@ -3351,7 +3239,7 @@ async function maybeHandleWellKnownOAuthRequest(request, response, requestUrl, s
|
|
|
3351
3239
|
function createGatewayServer(options) {
|
|
3352
3240
|
const debug = process.env.MCPX_GATEWAY_DEBUG === "1";
|
|
3353
3241
|
const runtime = {
|
|
3354
|
-
|
|
3242
|
+
upstreamConnections: new Map,
|
|
3355
3243
|
upstreamErrors: new Map
|
|
3356
3244
|
};
|
|
3357
3245
|
const server = http2.createServer(async (request, response) => {
|
|
@@ -3517,10 +3405,10 @@ function createGatewayServer(options) {
|
|
|
3517
3405
|
}
|
|
3518
3406
|
});
|
|
3519
3407
|
server.on("close", () => {
|
|
3520
|
-
for (const entry of runtime.
|
|
3521
|
-
|
|
3408
|
+
for (const entry of runtime.upstreamConnections.values()) {
|
|
3409
|
+
closeUpstreamConnection(entry);
|
|
3522
3410
|
}
|
|
3523
|
-
runtime.
|
|
3411
|
+
runtime.upstreamConnections.clear();
|
|
3524
3412
|
});
|
|
3525
3413
|
server.listen(options.port, "127.0.0.1");
|
|
3526
3414
|
return server;
|
package/dist/cli.js
CHANGED
package/dist/core/index.js
CHANGED
package/dist/gateway/server.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import http from "node:http";
|
|
2
2
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3
3
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
4
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
4
5
|
import { SecretsManager } from "../core/secrets.js";
|
|
5
6
|
import type { McpxConfig, UpstreamTokenCount } from "../types.js";
|
|
6
7
|
interface GatewayServerOptions {
|
|
@@ -8,22 +9,23 @@ interface GatewayServerOptions {
|
|
|
8
9
|
expectedToken: string;
|
|
9
10
|
secrets: SecretsManager;
|
|
10
11
|
}
|
|
11
|
-
interface
|
|
12
|
+
interface UpstreamConnection {
|
|
12
13
|
fingerprint: string;
|
|
13
14
|
client: Client;
|
|
14
|
-
transport: StdioClientTransport;
|
|
15
|
+
transport: StdioClientTransport | StreamableHTTPClientTransport;
|
|
15
16
|
}
|
|
16
|
-
interface
|
|
17
|
+
interface UpstreamConnectionEntry {
|
|
17
18
|
fingerprint: string;
|
|
18
|
-
promise: Promise<
|
|
19
|
+
promise: Promise<UpstreamConnection>;
|
|
19
20
|
}
|
|
20
21
|
interface GatewayRuntimeState {
|
|
21
|
-
|
|
22
|
+
upstreamConnections: Map<string, UpstreamConnectionEntry>;
|
|
22
23
|
tokenCache?: Map<string, {
|
|
23
24
|
fingerprint: string;
|
|
24
25
|
count: UpstreamTokenCount;
|
|
25
26
|
}>;
|
|
26
27
|
upstreamErrors?: Map<string, string>;
|
|
28
|
+
lastWwwAuthenticate?: Map<string, string>;
|
|
27
29
|
}
|
|
28
30
|
export declare function getUpstreamTokenCounts(config: McpxConfig, secrets: SecretsManager, runtime: GatewayRuntimeState): Promise<Record<string, UpstreamTokenCount>>;
|
|
29
31
|
export declare function createGatewayServer(options: GatewayServerOptions): http.Server;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/gateway/server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EACL,oBAAoB,EAGrB,MAAM,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/gateway/server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EACL,oBAAoB,EAGrB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,6BAA6B,EAAuB,MAAM,oDAAoD,CAAC;AAIxH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,KAAK,EAIV,UAAU,EAIV,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAarB,UAAU,oBAAoB;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;CACzB;AAED,UAAU,kBAAkB;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,oBAAoB,GAAG,6BAA6B,CAAC;CACjE;AAED,UAAU,uBAAuB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACtC;AAED,UAAU,mBAAmB;IAC3B,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IAC1D,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,kBAAkB,CAAA;KAAE,CAAC,CAAC;IAC7E,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,mBAAmB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AA2ND,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAgE7C;AAuvBD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAC,MAAM,CAkM9E"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const APP_VERSION = "0.1.
|
|
1
|
+
export declare const APP_VERSION = "0.1.87";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|