@oomol-lab/open-connector 1.6.2 → 1.6.4
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/README.md +27 -0
- package/assets/open-connector/catalog/apps/assured_platform.json +218 -0
- package/assets/open-connector/catalog/apps/baixiao.json +1080 -0
- package/assets/open-connector/catalog/apps/benchmarkone.json +956 -0
- package/assets/open-connector/catalog/apps/bing_webmaster.json +3097 -0
- package/assets/open-connector/catalog/apps/buzzsprout.json +1979 -0
- package/assets/open-connector/catalog/apps/feishu.json +13 -19
- package/assets/open-connector/catalog/apps/feishu_app_bot.json +12 -19
- package/assets/open-connector/catalog/apps/jin10.json +1 -1
- package/assets/open-connector/catalog/apps/linkfox.json +836 -0
- package/assets/open-connector/catalog/apps/metatraderapi.json +1077 -0
- package/assets/open-connector/catalog/apps/mktindex.json +2411 -0
- package/assets/open-connector/catalog/apps/mojo_helpdesk.json +660 -0
- package/assets/open-connector/catalog/apps/mumble.json +446 -0
- package/assets/open-connector/catalog/apps/notion.json +112 -3
- package/assets/open-connector/catalog/apps/omise.json +438 -0
- package/assets/open-connector/catalog/apps/panjiva.json +2858 -0
- package/assets/open-connector/catalog/apps/papertrail.json +449 -0
- package/assets/open-connector/catalog/apps/peec.json +747 -0
- package/assets/open-connector/catalog/apps/polygon_io.json +5156 -584
- package/assets/open-connector/catalog/apps/quant_data.json +1928 -0
- package/assets/open-connector/catalog/apps/riddle_quiz_maker.json +621 -0
- package/assets/open-connector/catalog/apps/slack.json +327 -4
- package/assets/open-connector/catalog/apps/slackbot.json +280 -3
- package/assets/open-connector/catalog/apps/templatedocs.json +438 -0
- package/assets/open-connector/catalog/apps/terminus_app.json +510 -0
- package/assets/open-connector/catalog/apps/ticket_tailor.json +584 -0
- package/assets/open-connector/catalog/apps/tongdaxin.json +2186 -82
- package/assets/open-connector/catalog/apps/veremark.json +514 -0
- package/assets/open-connector/catalog/apps/walletap.json +549 -0
- package/assets/open-connector/catalog/apps/xiaohongshu_store.json +955 -39
- package/assets/open-connector/catalog/apps-index.json +1 -1
- package/package.json +5 -1
- package/src/connection-service.d.ts +2 -0
- package/src/connection-service.js +8 -1
- package/src/core/provider-id.d.ts +5 -0
- package/src/core/provider-id.js +12 -0
- package/src/oauth/oauth-credential-refresh-service.js +2 -0
- package/src/oauth/oauth-flow-service.js +2 -0
- package/src/providers/action-contracts.generated.d.ts +27 -7
- package/src/providers/assured_platform/executors.d.ts +4 -0
- package/src/providers/assured_platform/executors.js +18 -0
- package/src/providers/assured_platform/runtime.d.ts +7 -0
- package/src/providers/assured_platform/runtime.js +108 -0
- package/src/providers/baixiao/actions.d.ts +2 -0
- package/src/providers/baixiao/actions.js +377 -0
- package/src/providers/baixiao/executors.d.ts +4 -0
- package/src/providers/baixiao/executors.js +106 -0
- package/src/providers/benchmarkone/executors.d.ts +4 -0
- package/src/providers/benchmarkone/executors.js +26 -0
- package/src/providers/benchmarkone/runtime.d.ts +12 -0
- package/src/providers/benchmarkone/runtime.js +113 -0
- package/src/providers/bing_webmaster/actions.d.ts +2 -0
- package/src/providers/bing_webmaster/actions.js +113 -0
- package/src/providers/bing_webmaster/executors.d.ts +4 -0
- package/src/providers/bing_webmaster/executors.js +104 -0
- package/src/providers/bing_webmaster/management-actions.d.ts +2 -0
- package/src/providers/bing_webmaster/management-actions.js +241 -0
- package/src/providers/bing_webmaster/reporting-actions.d.ts +2 -0
- package/src/providers/bing_webmaster/reporting-actions.js +300 -0
- package/src/providers/bing_webmaster/schemas.d.ts +33 -0
- package/src/providers/bing_webmaster/schemas.js +313 -0
- package/src/providers/buzzsprout/executors.d.ts +4 -0
- package/src/providers/buzzsprout/executors.js +21 -0
- package/src/providers/buzzsprout/runtime.d.ts +12 -0
- package/src/providers/buzzsprout/runtime.js +237 -0
- package/src/providers/dropbox/executors.js +21 -3
- package/src/providers/feishu/shared/drive-actions.d.ts +1 -0
- package/src/providers/feishu/shared/drive-actions.js +13 -9
- package/src/providers/feishu/shared/drive-runtime.js +15 -3
- package/src/providers/feishu/shared/wiki-actions.js +4 -2
- package/src/providers/feishu_app_bot/scopes.js +1 -1
- package/src/providers/hithink_finance/runtime.js +39 -60
- package/src/providers/linkfox/actions.js +2 -0
- package/src/providers/linkfox/runtime.js +70 -1
- package/src/providers/linkfox/sif-actions.d.ts +10 -0
- package/src/providers/linkfox/sif-actions.js +193 -0
- package/src/providers/mcp-client.d.ts +1 -0
- package/src/providers/mcp-client.js +41 -27
- package/src/providers/metatraderapi/executors.d.ts +4 -0
- package/src/providers/metatraderapi/executors.js +18 -0
- package/src/providers/metatraderapi/runtime.d.ts +7 -0
- package/src/providers/metatraderapi/runtime.js +216 -0
- package/src/providers/mktindex/actions-mmi.d.ts +2 -0
- package/src/providers/mktindex/actions-mmi.js +510 -0
- package/src/providers/mktindex/actions.d.ts +2 -0
- package/src/providers/mktindex/actions.js +2 -0
- package/src/providers/mktindex/executors.d.ts +4 -0
- package/src/providers/mktindex/executors.js +27 -0
- package/src/providers/mktindex/request.d.ts +17 -0
- package/src/providers/mktindex/request.js +48 -0
- package/src/providers/mktindex/runtime.d.ts +9 -0
- package/src/providers/mktindex/runtime.js +492 -0
- package/src/providers/mojo_helpdesk/executors.d.ts +4 -0
- package/src/providers/mojo_helpdesk/executors.js +18 -0
- package/src/providers/mojo_helpdesk/runtime.d.ts +7 -0
- package/src/providers/mojo_helpdesk/runtime.js +173 -0
- package/src/providers/mumble/executors.d.ts +4 -0
- package/src/providers/mumble/executors.js +99 -0
- package/src/providers/notion/executors.d.ts +9 -0
- package/src/providers/notion/executors.js +161 -6
- package/src/providers/omise/executors.d.ts +4 -0
- package/src/providers/omise/executors.js +120 -0
- package/src/providers/panjiva/actions.d.ts +14 -0
- package/src/providers/panjiva/actions.js +389 -0
- package/src/providers/panjiva/executors.d.ts +4 -0
- package/src/providers/panjiva/executors.js +136 -0
- package/src/providers/papertrail/executors.d.ts +4 -0
- package/src/providers/papertrail/executors.js +15 -0
- package/src/providers/papertrail/runtime.d.ts +7 -0
- package/src/providers/papertrail/runtime.js +167 -0
- package/src/providers/peec/executors.d.ts +4 -0
- package/src/providers/peec/executors.js +15 -0
- package/src/providers/peec/runtime.d.ts +7 -0
- package/src/providers/peec/runtime.js +128 -0
- package/src/providers/polygon_io/actions.d.ts +2 -0
- package/src/providers/polygon_io/actions.js +282 -0
- package/src/providers/polygon_io/expanded-actions.d.ts +2 -0
- package/src/providers/polygon_io/expanded-actions.js +375 -0
- package/src/providers/polygon_io/expanded-runtime.d.ts +16 -0
- package/src/providers/polygon_io/expanded-runtime.js +277 -0
- package/src/providers/polygon_io/runtime.js +21 -2
- package/src/providers/quant_data/executors.d.ts +4 -0
- package/src/providers/quant_data/executors.js +15 -0
- package/src/providers/quant_data/runtime.d.ts +7 -0
- package/src/providers/quant_data/runtime.js +118 -0
- package/src/providers/registry.generated.js +20 -0
- package/src/providers/riddle_quiz_maker/executors.d.ts +4 -0
- package/src/providers/riddle_quiz_maker/executors.js +15 -0
- package/src/providers/riddle_quiz_maker/runtime.d.ts +7 -0
- package/src/providers/riddle_quiz_maker/runtime.js +145 -0
- package/src/providers/sellersprite_mcp/executors.js +2 -1
- package/src/providers/slack/actions.js +106 -3
- package/src/providers/slack/runtime.js +262 -38
- package/src/providers/slackbot/actions.js +1 -1
- package/src/providers/templatedocs/executors.d.ts +4 -0
- package/src/providers/templatedocs/executors.js +18 -0
- package/src/providers/templatedocs/runtime.d.ts +13 -0
- package/src/providers/templatedocs/runtime.js +151 -0
- package/src/providers/terminus_app/executors.d.ts +4 -0
- package/src/providers/terminus_app/executors.js +15 -0
- package/src/providers/terminus_app/runtime.d.ts +7 -0
- package/src/providers/terminus_app/runtime.js +172 -0
- package/src/providers/ticket_tailor/executors.d.ts +4 -0
- package/src/providers/ticket_tailor/executors.js +15 -0
- package/src/providers/ticket_tailor/runtime.d.ts +7 -0
- package/src/providers/ticket_tailor/runtime.js +152 -0
- package/src/providers/tongdaxin/actions.d.ts +1 -0
- package/src/providers/tongdaxin/actions.js +6 -3
- package/src/providers/tongdaxin/executors.js +55 -13
- package/src/providers/tongdaxin/named-action-output.d.ts +1 -0
- package/src/providers/tongdaxin/named-action-output.js +143 -0
- package/src/providers/tongdaxin/named-action-routing.d.ts +9 -0
- package/src/providers/tongdaxin/named-action-routing.js +417 -0
- package/src/providers/tongdaxin/named-actions.d.ts +2 -0
- package/src/providers/tongdaxin/named-actions.js +373 -0
- package/src/providers/twenty_crm/runtime.js +4 -2
- package/src/providers/veremark/executors.d.ts +4 -0
- package/src/providers/veremark/executors.js +129 -0
- package/src/providers/walletap/executors.d.ts +4 -0
- package/src/providers/walletap/executors.js +15 -0
- package/src/providers/walletap/runtime.d.ts +7 -0
- package/src/providers/walletap/runtime.js +147 -0
- package/src/providers/weixin_official_account/access-token.js +31 -7
- package/src/providers/weixin_store/access-token.js +33 -7
- package/src/providers/xiaohongshu_store/executors.js +152 -3
- package/src/server/api/openapi.js +3 -0
- package/src/server/connector-assets.d.ts +4 -0
- package/src/server/connector-assets.js +12 -0
- package/src/server/connector-build.d.ts +33 -0
- package/src/server/connector-build.js +73 -0
- package/src/server/connector-runtime.d.ts +1 -2
- package/src/server/connector-runtime.js +2 -8
- package/src/server/server-assets.d.ts +0 -28
- package/src/server/server-assets.js +0 -50
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Client } from "@modelcontextprotocol/client";
|
|
1
|
+
import { Client, SdkHttpError } from "@modelcontextprotocol/client";
|
|
2
2
|
import { SSEClientTransport } from "@modelcontextprotocol/client";
|
|
3
3
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/client";
|
|
4
4
|
import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/client/validators/cf-worker";
|
|
@@ -6,33 +6,47 @@ const mcpConnectTimeoutMs = 60_000;
|
|
|
6
6
|
const modernMcpProtocolVersion = "2026-07-28";
|
|
7
7
|
const mcpJsonSchemaValidator = new CfWorkerJsonSchemaValidator();
|
|
8
8
|
export async function withMcpClient(options, run) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
9
|
+
let retriedSession = false;
|
|
10
|
+
while (true) {
|
|
11
|
+
const transportOptions = {
|
|
12
|
+
fetch: options.fetcher,
|
|
13
|
+
requestInit: {
|
|
14
|
+
headers: options.headers,
|
|
15
|
+
redirect: options.redirect,
|
|
16
|
+
signal: options.signal,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
const transport = options.transport === "sse"
|
|
20
|
+
? new SSEClientTransport(options.endpoint, transportOptions)
|
|
21
|
+
: new StreamableHTTPClientTransport(options.endpoint, transportOptions);
|
|
22
|
+
const client = new Client({ name: "open-connector", version: "1.0.0" }, {
|
|
23
|
+
jsonSchemaValidator: mcpJsonSchemaValidator,
|
|
24
|
+
versionNegotiation: { mode: resolveVersionNegotiationMode(options.protocolVersion) },
|
|
25
|
+
});
|
|
26
|
+
let connected = false;
|
|
27
|
+
try {
|
|
28
|
+
await client.connect(transport, { timeout: mcpConnectTimeoutMs, signal: options.signal });
|
|
29
|
+
connected = true;
|
|
30
|
+
return await run(client);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (connected &&
|
|
34
|
+
options.transport === "streamable_http" &&
|
|
35
|
+
options.retryOnSessionNotFound === true &&
|
|
36
|
+
!retriedSession &&
|
|
37
|
+
error instanceof SdkHttpError &&
|
|
38
|
+
error.status === 404) {
|
|
39
|
+
retriedSession = true;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
throw options.mapError ? options.mapError(error) : error;
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
if (options.terminateSession && transport instanceof StreamableHTTPClientTransport) {
|
|
46
|
+
await terminateMcpSession(transport);
|
|
47
|
+
}
|
|
48
|
+
await client.close().catch(() => undefined);
|
|
34
49
|
}
|
|
35
|
-
await client.close().catch(() => undefined);
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
52
|
async function terminateMcpSession(transport) {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CredentialValidators, ProviderExecutors, ProviderProxyExecutor } from "../../core/types.ts";
|
|
2
|
+
export declare const executors: ProviderExecutors;
|
|
3
|
+
export declare const proxy: ProviderProxyExecutor;
|
|
4
|
+
export declare const credentialValidators: CredentialValidators;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineApiKeyProviderExecutors, defineProviderProxy } from "../provider-runtime.js";
|
|
2
|
+
import { metatraderapiActionHandlers, metatraderapiApiBaseUrl, validateMetaTraderApiCredential } from "./runtime.js";
|
|
3
|
+
const service = "metatraderapi";
|
|
4
|
+
export const executors = defineApiKeyProviderExecutors(service, metatraderapiActionHandlers);
|
|
5
|
+
export const proxy = defineProviderProxy({
|
|
6
|
+
service,
|
|
7
|
+
baseUrl: metatraderapiApiBaseUrl,
|
|
8
|
+
auth: { type: "api_key_authorization", prefix: "Bearer " },
|
|
9
|
+
skipDnsValidation: true,
|
|
10
|
+
customizeRequest({ headers }) {
|
|
11
|
+
headers.set("accept", "application/json");
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
export const credentialValidators = {
|
|
15
|
+
apiKey(input, { fetcher, signal }) {
|
|
16
|
+
return validateMetaTraderApiCredential(input.apiKey, fetcher, signal);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CredentialValidationResult } from "../../core/types.ts";
|
|
2
|
+
import type { ApiKeyProviderContext, ProviderActionHandlers, ProviderFetch } from "../provider-runtime.ts";
|
|
3
|
+
export declare const metatraderapiApiBaseUrl = "https://metatraderapi.cloud/api/";
|
|
4
|
+
type MetaTraderHandler = (input: Record<string, unknown>, context: ApiKeyProviderContext) => Promise<unknown>;
|
|
5
|
+
export declare const metatraderapiActionHandlers: ProviderActionHandlers<"metatraderapi", MetaTraderHandler>;
|
|
6
|
+
export declare function validateMetaTraderApiCredential(apiKey: string, fetcher: ProviderFetch, signal?: AbortSignal): Promise<CredentialValidationResult>;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { compactObject, optionalInteger, optionalRecord, optionalString, recordOrEmpty } from "../../core/cast.js";
|
|
2
|
+
import { providerInputError, ProviderRequestError, providerResponseError, providerUserAgent, readProviderTextBody, requiredInputString, requiredResponseRecord, runProviderRequest, } from "../provider-runtime.js";
|
|
3
|
+
export const metatraderapiApiBaseUrl = "https://metatraderapi.cloud/api/";
|
|
4
|
+
const maxResponseBytes = 16 * 1024 * 1024;
|
|
5
|
+
export const metatraderapiActionHandlers = {
|
|
6
|
+
async list_sessions(_input, context) {
|
|
7
|
+
const payload = await requestMetaTrader({ ...context, path: "sessions/", phase: "execute" });
|
|
8
|
+
return { sessions: readArrayPayload(payload, "sessions", "MetaTraderAPI sessions response") };
|
|
9
|
+
},
|
|
10
|
+
async start_session(input, context) {
|
|
11
|
+
const payload = await requestMetaTrader({
|
|
12
|
+
...context,
|
|
13
|
+
path: "sessions/start/",
|
|
14
|
+
method: "POST",
|
|
15
|
+
phase: "execute",
|
|
16
|
+
body: {
|
|
17
|
+
account_id: requiredInputString(input.accountId, "accountId"),
|
|
18
|
+
password: requirePassword(input.password),
|
|
19
|
+
server: requiredInputString(input.server, "server"),
|
|
20
|
+
platform: requiredInputString(input.platform, "platform"),
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
return { session: requireMutationObject(payload, "MetaTraderAPI start session") };
|
|
24
|
+
},
|
|
25
|
+
async stop_session(input, context) {
|
|
26
|
+
return { result: recordOrEmpty(await requestSession(input, context, "stop/", "POST")) };
|
|
27
|
+
},
|
|
28
|
+
async close_all_sessions(_input, context) {
|
|
29
|
+
return {
|
|
30
|
+
result: recordOrEmpty(await requestMetaTrader({
|
|
31
|
+
...context,
|
|
32
|
+
path: "sessions/close-all/",
|
|
33
|
+
method: "POST",
|
|
34
|
+
phase: "execute",
|
|
35
|
+
})),
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
async get_account_info(input, context) {
|
|
39
|
+
return {
|
|
40
|
+
accountInfo: requiredResponseRecord(await requestSession(input, context, "account-info/"), "MetaTraderAPI account information response"),
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
async get_equity(input, context) {
|
|
44
|
+
return {
|
|
45
|
+
equity: requiredResponseRecord(await requestSession(input, context, "equity/"), "MetaTraderAPI equity response"),
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
async list_deals(input, context) {
|
|
49
|
+
const payload = await requestHistory(input, context, "history/deals/");
|
|
50
|
+
return { deals: readArrayPayload(payload, "deals", "MetaTraderAPI deals response") };
|
|
51
|
+
},
|
|
52
|
+
async list_history_orders(input, context) {
|
|
53
|
+
const payload = await requestHistory(input, context, "history/orders/");
|
|
54
|
+
return { orders: readArrayPayload(payload, "orders", "MetaTraderAPI order history response") };
|
|
55
|
+
},
|
|
56
|
+
async get_margin(input, context) {
|
|
57
|
+
return {
|
|
58
|
+
margin: requiredResponseRecord(await requestSession(input, context, "margin/"), "MetaTraderAPI margin response"),
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
async list_orders(input, context) {
|
|
62
|
+
const payload = await requestSession(input, context, "orders/");
|
|
63
|
+
return { orders: readArrayPayload(payload, "orders", "MetaTraderAPI pending orders response") };
|
|
64
|
+
},
|
|
65
|
+
async ping_session(input, context) {
|
|
66
|
+
return {
|
|
67
|
+
ping: requiredResponseRecord(await requestSession(input, context, "ping/"), "MetaTraderAPI ping response"),
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
async list_positions(input, context) {
|
|
71
|
+
const payload = await requestSession(input, context, "positions/");
|
|
72
|
+
return { positions: readArrayPayload(payload, "positions", "MetaTraderAPI positions response") };
|
|
73
|
+
},
|
|
74
|
+
async get_session_status(input, context) {
|
|
75
|
+
return {
|
|
76
|
+
status: requiredResponseRecord(await requestSession(input, context, "status/"), "MetaTraderAPI session status response"),
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
async list_symbols(input, context) {
|
|
80
|
+
const symbols = readArrayPayload(await requestSession(input, context, "symbols/"), "symbols", "MetaTraderAPI symbols response");
|
|
81
|
+
if (!symbols.every((value) => typeof value === "string")) {
|
|
82
|
+
throw providerResponseError("MetaTraderAPI symbols response must contain only strings");
|
|
83
|
+
}
|
|
84
|
+
return { symbols };
|
|
85
|
+
},
|
|
86
|
+
async get_symbol(input, context) {
|
|
87
|
+
const symbol = requiredInputString(input.symbol, "symbol");
|
|
88
|
+
return {
|
|
89
|
+
symbol: requiredResponseRecord(await requestSession(input, context, `symbols/${encodeURIComponent(symbol)}/`), "MetaTraderAPI symbol response"),
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
export async function validateMetaTraderApiCredential(apiKey, fetcher, signal) {
|
|
94
|
+
const payload = await requestMetaTrader({ apiKey, fetcher, signal, path: "sessions/", phase: "validate" });
|
|
95
|
+
const sessions = readArrayPayload(payload, "sessions", "MetaTraderAPI sessions response");
|
|
96
|
+
return {
|
|
97
|
+
profile: { displayName: "MetaTraderAPI API Key" },
|
|
98
|
+
grantedScopes: [],
|
|
99
|
+
metadata: {
|
|
100
|
+
apiBaseUrl: metatraderapiApiBaseUrl.slice(0, -1),
|
|
101
|
+
validationEndpoint: "/sessions/",
|
|
102
|
+
activeSessionCount: sessions.length,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async function requestSession(input, context, suffix, method = "GET") {
|
|
107
|
+
const sessionId = requiredInputString(input.sessionId, "sessionId");
|
|
108
|
+
return requestMetaTrader({
|
|
109
|
+
...context,
|
|
110
|
+
path: `sessions/${encodeURIComponent(sessionId)}/${suffix}`,
|
|
111
|
+
method,
|
|
112
|
+
phase: "execute",
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async function requestHistory(input, context, suffix) {
|
|
116
|
+
const sessionId = requiredInputString(input.sessionId, "sessionId");
|
|
117
|
+
return requestMetaTrader({
|
|
118
|
+
...context,
|
|
119
|
+
path: `sessions/${encodeURIComponent(sessionId)}/${suffix}`,
|
|
120
|
+
query: compactObject({
|
|
121
|
+
date_from: optionalString(input.dateFrom),
|
|
122
|
+
date_to: optionalString(input.dateTo),
|
|
123
|
+
days_back: optionalInteger(input.daysBack),
|
|
124
|
+
}),
|
|
125
|
+
phase: "execute",
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async function requestMetaTrader(input) {
|
|
129
|
+
try {
|
|
130
|
+
return await runProviderRequest({ label: "MetaTraderAPI", signal: input.signal }, async (signal) => {
|
|
131
|
+
const url = new URL(input.path, metatraderapiApiBaseUrl);
|
|
132
|
+
for (const [key, value] of Object.entries(input.query ?? {})) {
|
|
133
|
+
if (value !== undefined)
|
|
134
|
+
url.searchParams.set(key, String(value));
|
|
135
|
+
}
|
|
136
|
+
const headers = new Headers({
|
|
137
|
+
accept: "application/json",
|
|
138
|
+
authorization: `Bearer ${input.apiKey}`,
|
|
139
|
+
"user-agent": providerUserAgent,
|
|
140
|
+
});
|
|
141
|
+
if (input.body !== undefined)
|
|
142
|
+
headers.set("content-type", "application/json");
|
|
143
|
+
const response = await input.fetcher(url, {
|
|
144
|
+
method: input.method ?? "GET",
|
|
145
|
+
headers,
|
|
146
|
+
body: input.body === undefined ? undefined : JSON.stringify(input.body),
|
|
147
|
+
signal,
|
|
148
|
+
});
|
|
149
|
+
const payload = await readPayload(response);
|
|
150
|
+
if (!response.ok)
|
|
151
|
+
throw createMetaTraderError(response.status, payload, input.phase);
|
|
152
|
+
return payload;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (input.phase === "execute" &&
|
|
157
|
+
input.method === "POST" &&
|
|
158
|
+
error instanceof ProviderRequestError &&
|
|
159
|
+
error.status >= 500) {
|
|
160
|
+
throw new ProviderRequestError(error.status, `${error.message}; the operation may have completed upstream. Check the current session or trading state before retrying.`, { retryable: false, upstreamCompleted: "unknown" });
|
|
161
|
+
}
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function readPayload(response) {
|
|
166
|
+
const text = await readProviderTextBody(response, "MetaTraderAPI response", maxResponseBytes);
|
|
167
|
+
if (text.trim() === "")
|
|
168
|
+
return null;
|
|
169
|
+
try {
|
|
170
|
+
return JSON.parse(text);
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
if (!response.ok)
|
|
174
|
+
return text.trim();
|
|
175
|
+
throw new ProviderRequestError(502, "MetaTraderAPI returned invalid JSON", error);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function createMetaTraderError(status, payload, phase) {
|
|
179
|
+
const message = errorMessage(payload) ?? `MetaTraderAPI request failed with status ${status}`;
|
|
180
|
+
if (phase === "validate" && status >= 400 && status < 500) {
|
|
181
|
+
return providerInputError(message);
|
|
182
|
+
}
|
|
183
|
+
if (status === 400 || status === 404)
|
|
184
|
+
return providerInputError(message);
|
|
185
|
+
return new ProviderRequestError(status || 502, message);
|
|
186
|
+
}
|
|
187
|
+
function errorMessage(payload) {
|
|
188
|
+
if (typeof payload === "string" && payload.trim())
|
|
189
|
+
return payload.trim();
|
|
190
|
+
const record = optionalRecord(payload);
|
|
191
|
+
for (const key of ["detail", "message", "error"]) {
|
|
192
|
+
const value = optionalString(record?.[key])?.trim();
|
|
193
|
+
if (value)
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
function readArrayPayload(payload, field, label) {
|
|
199
|
+
if (Array.isArray(payload))
|
|
200
|
+
return payload;
|
|
201
|
+
const record = optionalRecord(payload);
|
|
202
|
+
if (Array.isArray(record?.[field]))
|
|
203
|
+
return record[field];
|
|
204
|
+
throw providerResponseError(`${label} must contain an array`);
|
|
205
|
+
}
|
|
206
|
+
function requireMutationObject(payload, label) {
|
|
207
|
+
const record = optionalRecord(payload);
|
|
208
|
+
if (record)
|
|
209
|
+
return record;
|
|
210
|
+
throw new ProviderRequestError(502, `${label} returned an empty or invalid response; the operation may have completed upstream. Check the current session or trading state before retrying.`, { retryable: false, upstreamCompleted: "unknown" });
|
|
211
|
+
}
|
|
212
|
+
function requirePassword(value) {
|
|
213
|
+
if (typeof value !== "string" || value.length === 0)
|
|
214
|
+
throw providerInputError("password is required");
|
|
215
|
+
return value;
|
|
216
|
+
}
|