@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
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { compactObject, optionalInteger, optionalString } from "../../core/cast.js";
|
|
2
|
+
import { readProviderTextBody } from "../provider-runtime.js";
|
|
3
|
+
import { providerInputError, providerUserAgent, ProviderRequestError, requiredInputString, runProviderRequest, } from "../provider-runtime.js";
|
|
4
|
+
export const walletapApiBaseUrl = "https://api.walletap.io";
|
|
5
|
+
export const walletapActionHandlers = {
|
|
6
|
+
list_templates(input, context) {
|
|
7
|
+
return requestWalletapData({
|
|
8
|
+
apiKey: context.apiKey,
|
|
9
|
+
path: "/api/templates",
|
|
10
|
+
query: { limit: optionalInteger(input.limit), starting_after: optionalString(input.startingAfter) },
|
|
11
|
+
fetcher: context.fetcher,
|
|
12
|
+
signal: context.signal,
|
|
13
|
+
});
|
|
14
|
+
},
|
|
15
|
+
get_template(input, context) {
|
|
16
|
+
return requestWalletapData({
|
|
17
|
+
apiKey: context.apiKey,
|
|
18
|
+
path: `/api/templates/${encodeURIComponent(requiredInputString(input.templateId, "templateId"))}`,
|
|
19
|
+
fetcher: context.fetcher,
|
|
20
|
+
signal: context.signal,
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
list_passes(input, context) {
|
|
24
|
+
return requestWalletapData({
|
|
25
|
+
apiKey: context.apiKey,
|
|
26
|
+
path: "/api/passes",
|
|
27
|
+
query: {
|
|
28
|
+
templateId: requiredInputString(input.templateId, "templateId"),
|
|
29
|
+
limit: optionalInteger(input.limit),
|
|
30
|
+
startAfter: optionalString(input.startAfter),
|
|
31
|
+
endBefore: optionalString(input.endBefore),
|
|
32
|
+
status: optionalString(input.status),
|
|
33
|
+
},
|
|
34
|
+
fetcher: context.fetcher,
|
|
35
|
+
signal: context.signal,
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
search_passes(input, context) {
|
|
39
|
+
return requestWalletapData({
|
|
40
|
+
apiKey: context.apiKey,
|
|
41
|
+
path: "/api/passes/search",
|
|
42
|
+
query: {
|
|
43
|
+
templateId: requiredInputString(input.templateId, "templateId"),
|
|
44
|
+
searchQuery: requiredInputString(input.searchQuery, "searchQuery"),
|
|
45
|
+
},
|
|
46
|
+
fetcher: context.fetcher,
|
|
47
|
+
signal: context.signal,
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
get_pass(input, context) {
|
|
51
|
+
requirePassIdentifier(input);
|
|
52
|
+
return requestWalletapData({
|
|
53
|
+
apiKey: context.apiKey,
|
|
54
|
+
path: "/api/pass",
|
|
55
|
+
query: compactObject({
|
|
56
|
+
id: optionalString(input.id),
|
|
57
|
+
externalId: optionalString(input.externalId),
|
|
58
|
+
templateId: optionalString(input.templateId),
|
|
59
|
+
includeTemplate: typeof input.includeTemplate === "boolean" ? input.includeTemplate : undefined,
|
|
60
|
+
locale: optionalString(input.locale),
|
|
61
|
+
}),
|
|
62
|
+
fetcher: context.fetcher,
|
|
63
|
+
signal: context.signal,
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
create_pass(input, context) {
|
|
67
|
+
return requestWalletapData({
|
|
68
|
+
apiKey: context.apiKey,
|
|
69
|
+
method: "POST",
|
|
70
|
+
path: "/api/pass",
|
|
71
|
+
body: input,
|
|
72
|
+
fetcher: context.fetcher,
|
|
73
|
+
signal: context.signal,
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
update_pass(input, context) {
|
|
77
|
+
requirePassIdentifier(input);
|
|
78
|
+
return requestWalletapData({
|
|
79
|
+
apiKey: context.apiKey,
|
|
80
|
+
method: "PATCH",
|
|
81
|
+
path: "/api/pass",
|
|
82
|
+
body: input,
|
|
83
|
+
fetcher: context.fetcher,
|
|
84
|
+
signal: context.signal,
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
notify_pass(input, context) {
|
|
88
|
+
const passId = requiredInputString(input.passId, "passId");
|
|
89
|
+
const { passId: _, ...body } = input;
|
|
90
|
+
return requestWalletapData({
|
|
91
|
+
apiKey: context.apiKey,
|
|
92
|
+
method: "POST",
|
|
93
|
+
path: `/api/pass/${encodeURIComponent(passId)}/notify`,
|
|
94
|
+
body,
|
|
95
|
+
fetcher: context.fetcher,
|
|
96
|
+
signal: context.signal,
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
export async function validateWalletapCredential(apiKey, fetcher, signal) {
|
|
101
|
+
await requestWalletapData({ apiKey, path: "/api/templates", query: { limit: 1 }, fetcher, signal });
|
|
102
|
+
return { profile: { accountId: "walletap", displayName: "Walletap API Key" }, grantedScopes: [], metadata: {} };
|
|
103
|
+
}
|
|
104
|
+
function requirePassIdentifier(input) {
|
|
105
|
+
if (optionalString(input.id) || (optionalString(input.externalId) && optionalString(input.templateId)))
|
|
106
|
+
return;
|
|
107
|
+
throw providerInputError("id or externalId together with templateId is required");
|
|
108
|
+
}
|
|
109
|
+
async function requestWalletapData(input) {
|
|
110
|
+
return runProviderRequest({ label: "Walletap", signal: input.signal }, async (signal) => {
|
|
111
|
+
const url = new URL(input.path, walletapApiBaseUrl);
|
|
112
|
+
for (const [key, value] of Object.entries(input.query ?? {}))
|
|
113
|
+
if (value !== undefined)
|
|
114
|
+
url.searchParams.set(key, String(value));
|
|
115
|
+
const response = await input.fetcher(url, {
|
|
116
|
+
method: input.method ?? "GET",
|
|
117
|
+
headers: {
|
|
118
|
+
accept: "application/json",
|
|
119
|
+
"content-type": "application/json",
|
|
120
|
+
"user-agent": providerUserAgent,
|
|
121
|
+
"x-api-key": input.apiKey,
|
|
122
|
+
},
|
|
123
|
+
body: input.body === undefined ? undefined : JSON.stringify(input.body),
|
|
124
|
+
signal,
|
|
125
|
+
});
|
|
126
|
+
const payload = parseWalletapPayload(await readProviderTextBody(response, "Walletap response"));
|
|
127
|
+
if (!response.ok)
|
|
128
|
+
throw new ProviderRequestError(response.status, readWalletapError(payload) ?? `Walletap request failed with HTTP ${response.status}`, payload);
|
|
129
|
+
return { data: payload };
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function parseWalletapPayload(text) {
|
|
133
|
+
if (!text)
|
|
134
|
+
return {};
|
|
135
|
+
try {
|
|
136
|
+
return JSON.parse(text);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
throw new ProviderRequestError(502, "Walletap returned an invalid JSON response");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function readWalletapError(payload) {
|
|
143
|
+
if (typeof payload !== "object" || payload === null)
|
|
144
|
+
return undefined;
|
|
145
|
+
const record = payload;
|
|
146
|
+
return optionalString(record.error) ?? optionalString(record.message);
|
|
147
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { optionalInteger, optionalNumber, optionalRecord, optionalString } from "../../core/cast.js";
|
|
2
3
|
import { ProviderRequestError, providerResponseError, providerUserAgent, requiredInputString, runProviderRequest, } from "../provider-runtime.js";
|
|
3
4
|
const wechatStableTokenUrl = "https://api.weixin.qq.com/cgi-bin/stable_token";
|
|
@@ -6,6 +7,10 @@ const accessTokenRefreshSkewMs = 120_000;
|
|
|
6
7
|
const ipWhitelistHint = "Add this runtime's public egress IP to the official account's API IP whitelist in the 微信开发者平台 console (公众号 → 基础信息 → 开发密钥 → API IP白名单) and try again.";
|
|
7
8
|
const accessTokenCache = new Map();
|
|
8
9
|
const accessTokenInFlight = new Map();
|
|
10
|
+
const accessTokenRefreshInFlight = new Map();
|
|
11
|
+
function accessTokenCacheKey(credential) {
|
|
12
|
+
return createHash("sha256").update(credential.appId).update("\0").update(credential.appSecret).digest("hex");
|
|
13
|
+
}
|
|
9
14
|
export function readWechatOfficialAccountCredential(values) {
|
|
10
15
|
return {
|
|
11
16
|
appId: requiredInputString(values.appId, "appId"),
|
|
@@ -20,18 +25,37 @@ export function readWechatOfficialAccountCredential(values) {
|
|
|
20
25
|
* one invalidates the previous token, so duplicate mints must not happen.
|
|
21
26
|
*/
|
|
22
27
|
export async function getWechatAccessToken(input) {
|
|
23
|
-
const cacheKey =
|
|
28
|
+
const cacheKey = accessTokenCacheKey(input.credential);
|
|
29
|
+
const refreshPending = accessTokenRefreshInFlight.get(cacheKey);
|
|
30
|
+
if (refreshPending)
|
|
31
|
+
return refreshPending;
|
|
24
32
|
const pending = accessTokenInFlight.get(cacheKey);
|
|
25
|
-
if (
|
|
26
|
-
|
|
33
|
+
if (!input.forceRefresh) {
|
|
34
|
+
if (pending)
|
|
35
|
+
return pending;
|
|
36
|
+
const request = mintAndCacheAccessToken(input, cacheKey);
|
|
37
|
+
accessTokenInFlight.set(cacheKey, request);
|
|
38
|
+
try {
|
|
39
|
+
return await request;
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
if (accessTokenInFlight.get(cacheKey) === request)
|
|
43
|
+
accessTokenInFlight.delete(cacheKey);
|
|
44
|
+
}
|
|
27
45
|
}
|
|
28
|
-
const
|
|
29
|
-
|
|
46
|
+
const refresh = (async () => {
|
|
47
|
+
if (pending)
|
|
48
|
+
await pending.catch(() => undefined);
|
|
49
|
+
return mintAndCacheAccessToken(input, cacheKey);
|
|
50
|
+
})();
|
|
51
|
+
accessTokenRefreshInFlight.set(cacheKey, refresh);
|
|
30
52
|
try {
|
|
31
|
-
return await
|
|
53
|
+
return await refresh;
|
|
32
54
|
}
|
|
33
55
|
finally {
|
|
34
|
-
|
|
56
|
+
if (accessTokenRefreshInFlight.get(cacheKey) === refresh) {
|
|
57
|
+
accessTokenRefreshInFlight.delete(cacheKey);
|
|
58
|
+
}
|
|
35
59
|
}
|
|
36
60
|
}
|
|
37
61
|
async function mintAndCacheAccessToken(input, cacheKey) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { optionalInteger, optionalNumber, optionalRecord, optionalString } from "../../core/cast.js";
|
|
2
3
|
import { ProviderRequestError, providerResponseError, providerUserAgent, requiredInputString, runProviderRequest, } from "../provider-runtime.js";
|
|
3
4
|
const wechatStableTokenUrl = "https://api.weixin.qq.com/cgi-bin/stable_token";
|
|
@@ -5,6 +6,7 @@ const defaultAccessTokenTtlSeconds = 7200;
|
|
|
5
6
|
const accessTokenRefreshSkewMs = 120_000;
|
|
6
7
|
const accessTokenCache = new Map();
|
|
7
8
|
const accessTokenInFlight = new Map();
|
|
9
|
+
const accessTokenRefreshInFlight = new Map();
|
|
8
10
|
export function readWeixinStoreCredential(values) {
|
|
9
11
|
return {
|
|
10
12
|
appId: requiredInputString(values.appId, "appId"),
|
|
@@ -24,18 +26,42 @@ export function readWeixinStoreCredential(values) {
|
|
|
24
26
|
* follow-up request; the shared mint still runs under the default 30 s timeout.
|
|
25
27
|
*/
|
|
26
28
|
export async function getWechatAccessToken(input) {
|
|
27
|
-
const cacheKey =
|
|
29
|
+
const cacheKey = createHash("sha256")
|
|
30
|
+
.update(input.credential.appId)
|
|
31
|
+
.update("\0")
|
|
32
|
+
.update(input.credential.appSecret)
|
|
33
|
+
.digest("hex");
|
|
34
|
+
const refreshPending = accessTokenRefreshInFlight.get(cacheKey);
|
|
35
|
+
if (refreshPending)
|
|
36
|
+
return refreshPending;
|
|
28
37
|
const pending = accessTokenInFlight.get(cacheKey);
|
|
29
|
-
if (
|
|
30
|
-
|
|
38
|
+
if (input.rejectedToken === undefined) {
|
|
39
|
+
if (pending)
|
|
40
|
+
return pending;
|
|
41
|
+
const request = mintAndCacheAccessToken(input, cacheKey);
|
|
42
|
+
accessTokenInFlight.set(cacheKey, request);
|
|
43
|
+
try {
|
|
44
|
+
return await request;
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
if (accessTokenInFlight.get(cacheKey) === request)
|
|
48
|
+
accessTokenInFlight.delete(cacheKey);
|
|
49
|
+
}
|
|
31
50
|
}
|
|
32
|
-
const
|
|
33
|
-
|
|
51
|
+
const refresh = (async () => {
|
|
52
|
+
const pendingToken = pending ? await pending.catch(() => undefined) : undefined;
|
|
53
|
+
if (pendingToken !== undefined && pendingToken !== input.rejectedToken)
|
|
54
|
+
return pendingToken;
|
|
55
|
+
return mintAndCacheAccessToken(input, cacheKey);
|
|
56
|
+
})();
|
|
57
|
+
accessTokenRefreshInFlight.set(cacheKey, refresh);
|
|
34
58
|
try {
|
|
35
|
-
return await
|
|
59
|
+
return await refresh;
|
|
36
60
|
}
|
|
37
61
|
finally {
|
|
38
|
-
|
|
62
|
+
if (accessTokenRefreshInFlight.get(cacheKey) === refresh) {
|
|
63
|
+
accessTokenRefreshInFlight.delete(cacheKey);
|
|
64
|
+
}
|
|
39
65
|
}
|
|
40
66
|
}
|
|
41
67
|
async function mintAndCacheAccessToken(input, cacheKey) {
|
|
@@ -36,6 +36,15 @@ const actionMethodByName = {
|
|
|
36
36
|
list_categories: "common.getCategories",
|
|
37
37
|
get_category_attributes: "common.getAttributeLists",
|
|
38
38
|
list_express_companies: "common.getExpressCompanyList",
|
|
39
|
+
list_item_skus: "product.getDetailSkuList",
|
|
40
|
+
create_item: "product.createItemAndSku",
|
|
41
|
+
update_item: "product.updateItemAndSku",
|
|
42
|
+
upload_material: "material.uploadMaterial",
|
|
43
|
+
list_materials: "material.queryMaterial",
|
|
44
|
+
search_brands: "common.brandSearch",
|
|
45
|
+
list_carriage_templates: "common.getCarriageTemplateList",
|
|
46
|
+
list_logistics_plans: "common.getLogisticsList",
|
|
47
|
+
list_address_records: "common.getAddressRecord",
|
|
39
48
|
};
|
|
40
49
|
const handlers = mapProviderActionSources("xiaohongshu_store", actionMethodByName, (actionName, method) => async (input, context) => {
|
|
41
50
|
const data = await requestXiaohongshuStore({
|
|
@@ -147,9 +156,14 @@ async function requestXiaohongshuStore(input) {
|
|
|
147
156
|
function isXiaohongshuStoreSuccess(payload) {
|
|
148
157
|
if (payload.success === false)
|
|
149
158
|
return false;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
159
|
+
const errorCode = optionalInteger(payload.error_code) ?? optionalInteger(payload.errorCode);
|
|
160
|
+
// The item publish APIs report some business rejections as { success: true, error_code: 50209,
|
|
161
|
+
// error_msg: "..." } with no data; without this check the message would be lost behind a generic
|
|
162
|
+
// "invalid item" response error.
|
|
163
|
+
if (payload.success === true) {
|
|
164
|
+
return payload.data != null || errorCode === undefined || errorCode === 0;
|
|
165
|
+
}
|
|
166
|
+
return errorCode === 0;
|
|
153
167
|
}
|
|
154
168
|
// The newer after-sale APIs wrap their payload in a second { code, msg, success, data }
|
|
155
169
|
// envelope inside the standard one; both layers have to succeed.
|
|
@@ -383,6 +397,61 @@ function buildActionParameters(actionName, input) {
|
|
|
383
397
|
}
|
|
384
398
|
case "adjust_sku_stock":
|
|
385
399
|
return { skuId: requiredInputString(input.skuId, "skuId"), qty: integer(input.qty, "qty", providerInputError) };
|
|
400
|
+
case "list_item_skus":
|
|
401
|
+
return compactObject({
|
|
402
|
+
id: optionalString(input.id),
|
|
403
|
+
createTimeFrom: optionalInteger(input.createTimeFrom),
|
|
404
|
+
createTimeTo: optionalInteger(input.createTimeTo),
|
|
405
|
+
updateTimeFrom: optionalInteger(input.updateTimeFrom),
|
|
406
|
+
updateTimeTo: optionalInteger(input.updateTimeTo),
|
|
407
|
+
buyable: optionalBoolean(input.buyable),
|
|
408
|
+
stockGte: optionalInteger(input.stockGte),
|
|
409
|
+
stockLte: optionalInteger(input.stockLte),
|
|
410
|
+
barcode: optionalString(input.barcode),
|
|
411
|
+
scSkucode: optionalString(input.scSkucode),
|
|
412
|
+
singlePackOnly: optionalBoolean(input.singlePackOnly),
|
|
413
|
+
lastId: optionalString(input.lastId),
|
|
414
|
+
isChannel: optionalBoolean(input.isChannel),
|
|
415
|
+
pageNo: optionalInteger(input.pageNo) ?? 1,
|
|
416
|
+
pageSize: optionalInteger(input.pageSize) ?? 50,
|
|
417
|
+
});
|
|
418
|
+
case "create_item":
|
|
419
|
+
return buildItemParameters(input, false);
|
|
420
|
+
case "update_item":
|
|
421
|
+
return buildItemParameters(input, true);
|
|
422
|
+
case "upload_material":
|
|
423
|
+
return {
|
|
424
|
+
name: requiredInputString(input.name, "name"),
|
|
425
|
+
type: requiredInputString(input.type, "type"),
|
|
426
|
+
materialContent: requiredInputString(input.contentBase64, "contentBase64"),
|
|
427
|
+
};
|
|
428
|
+
case "list_materials":
|
|
429
|
+
return compactObject({
|
|
430
|
+
materialId: optionalString(input.materialId),
|
|
431
|
+
name: optionalString(input.name),
|
|
432
|
+
type: optionalString(input.type),
|
|
433
|
+
status: optionalInteger(input.status),
|
|
434
|
+
createTimeFrom: optionalInteger(input.createTimeFrom),
|
|
435
|
+
createTimeTo: optionalInteger(input.createTimeTo),
|
|
436
|
+
ascByCreateTime: optionalBoolean(input.ascByCreateTime),
|
|
437
|
+
pageNo: optionalInteger(input.pageNo) ?? 1,
|
|
438
|
+
pageSize: optionalInteger(input.pageSize) ?? 50,
|
|
439
|
+
});
|
|
440
|
+
case "search_brands":
|
|
441
|
+
return {
|
|
442
|
+
categoryId: requiredInputString(input.categoryId, "categoryId"),
|
|
443
|
+
keyword: optionalString(input.keyword),
|
|
444
|
+
pageNo: optionalInteger(input.pageNo) ?? 1,
|
|
445
|
+
pageSize: optionalInteger(input.pageSize) ?? 20,
|
|
446
|
+
};
|
|
447
|
+
case "list_carriage_templates":
|
|
448
|
+
case "list_address_records":
|
|
449
|
+
return {
|
|
450
|
+
pageIndex: optionalInteger(input.pageIndex) ?? 1,
|
|
451
|
+
pageSize: optionalInteger(input.pageSize) ?? 20,
|
|
452
|
+
};
|
|
453
|
+
case "list_logistics_plans":
|
|
454
|
+
return {};
|
|
386
455
|
case "list_categories":
|
|
387
456
|
return compactObject({ categoryId: optionalString(input.categoryId) });
|
|
388
457
|
case "get_category_attributes":
|
|
@@ -488,6 +557,50 @@ function normalizeActionOutput(actionName, data) {
|
|
|
488
557
|
if (!record)
|
|
489
558
|
throw providerResponseError("Xiaohongshu returned an invalid SKU stock result");
|
|
490
559
|
return { stock: record };
|
|
560
|
+
case "list_item_skus":
|
|
561
|
+
if (!record)
|
|
562
|
+
throw providerResponseError("Xiaohongshu returned an invalid item SKU list");
|
|
563
|
+
return {
|
|
564
|
+
items: requireArray(record.data, "item SKU list"),
|
|
565
|
+
total: requireNonNegativeInteger(record.total, "item total"),
|
|
566
|
+
pageNo: optionalInteger(record.pageNO) ?? 1,
|
|
567
|
+
pageSize: optionalInteger(record.pageSize) ?? 50,
|
|
568
|
+
};
|
|
569
|
+
case "create_item":
|
|
570
|
+
case "update_item":
|
|
571
|
+
if (!record)
|
|
572
|
+
throw providerResponseError("Xiaohongshu returned an invalid item");
|
|
573
|
+
return { item: record };
|
|
574
|
+
case "upload_material":
|
|
575
|
+
if (!record)
|
|
576
|
+
throw providerResponseError("Xiaohongshu returned an invalid material");
|
|
577
|
+
return { material: record };
|
|
578
|
+
case "list_materials":
|
|
579
|
+
if (!record)
|
|
580
|
+
throw providerResponseError("Xiaohongshu returned an invalid material list");
|
|
581
|
+
return { materials: requireArray(record.materialDetailList, "material list") };
|
|
582
|
+
case "search_brands":
|
|
583
|
+
if (!record)
|
|
584
|
+
throw providerResponseError("Xiaohongshu returned an invalid brand list");
|
|
585
|
+
return { brands: requireArray(record.brands, "brand list") };
|
|
586
|
+
case "list_carriage_templates":
|
|
587
|
+
if (!record)
|
|
588
|
+
throw providerResponseError("Xiaohongshu returned an invalid carriage template list");
|
|
589
|
+
return {
|
|
590
|
+
templates: requireArray(record.carriageTemplateList, "carriage template list"),
|
|
591
|
+
total: requireNonNegativeInteger(record.totalCount, "carriage template total"),
|
|
592
|
+
};
|
|
593
|
+
case "list_logistics_plans":
|
|
594
|
+
if (!record)
|
|
595
|
+
throw providerResponseError("Xiaohongshu returned an invalid logistics plan list");
|
|
596
|
+
return { plans: requireArray(record.logisticsPlans, "logistics plan list") };
|
|
597
|
+
case "list_address_records":
|
|
598
|
+
if (!record)
|
|
599
|
+
throw providerResponseError("Xiaohongshu returned an invalid address record list");
|
|
600
|
+
return {
|
|
601
|
+
addresses: requireArray(record.sellerAddressRecordList, "address record list"),
|
|
602
|
+
total: requireNonNegativeInteger(record.total, "address record total"),
|
|
603
|
+
};
|
|
491
604
|
case "list_categories":
|
|
492
605
|
if (!record)
|
|
493
606
|
throw providerResponseError("Xiaohongshu returned an invalid category list");
|
|
@@ -510,6 +623,42 @@ function normalizeActionOutput(actionName, data) {
|
|
|
510
623
|
return { success: true };
|
|
511
624
|
}
|
|
512
625
|
}
|
|
626
|
+
function buildItemParameters(input, update) {
|
|
627
|
+
const images = looseArray(input.images);
|
|
628
|
+
if (images.length === 0) {
|
|
629
|
+
throw providerInputError("images must be a non-empty array");
|
|
630
|
+
}
|
|
631
|
+
const skuListField = update ? "updateSkuList" : "createSkuList";
|
|
632
|
+
const skuList = looseArray(input[skuListField]);
|
|
633
|
+
if (skuList.length === 0) {
|
|
634
|
+
throw providerInputError(`${skuListField} must be a non-empty array`);
|
|
635
|
+
}
|
|
636
|
+
return compactObject({
|
|
637
|
+
itemId: update ? requiredInputString(input.itemId, "itemId") : undefined,
|
|
638
|
+
name: requiredInputString(input.name, "name"),
|
|
639
|
+
categoryId: requiredInputString(input.categoryId, "categoryId"),
|
|
640
|
+
shippingTemplateId: requiredInputString(input.shippingTemplateId, "shippingTemplateId"),
|
|
641
|
+
shippingGrossWeight: optionalInteger(input.shippingGrossWeight),
|
|
642
|
+
images,
|
|
643
|
+
brandId: optionalString(input.brandId),
|
|
644
|
+
attributes: optionalNonEmptyArray(input.attributes),
|
|
645
|
+
variantIds: optionalStringArray(input.variantIds),
|
|
646
|
+
articleNo: optionalString(input.articleNo),
|
|
647
|
+
description: optionalString(input.description),
|
|
648
|
+
itemShortTitle: optionalString(input.itemShortTitle),
|
|
649
|
+
deliveryMode: optionalInteger(input.deliveryMode),
|
|
650
|
+
freeReturn: optionalInteger(input.freeReturn),
|
|
651
|
+
videos: optionalNonEmptyArray(input.videos),
|
|
652
|
+
imageDescriptions: optionalNonEmptyArray(input.imageDescriptions),
|
|
653
|
+
createSkuList: update ? optionalNonEmptyArray(input.createSkuList) : undefined,
|
|
654
|
+
deleteSkuIdList: update ? optionalStringArray(input.deleteSkuIdList) : undefined,
|
|
655
|
+
[skuListField]: skuList,
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
function optionalNonEmptyArray(value) {
|
|
659
|
+
const items = looseArray(value);
|
|
660
|
+
return items.length > 0 ? items : undefined;
|
|
661
|
+
}
|
|
513
662
|
function requireOrderListTimestamp(value, fieldName) {
|
|
514
663
|
const timestamp = integer(value, fieldName, providerInputError);
|
|
515
664
|
// Anything this large is a millisecond timestamp, which the order list would silently misread.
|
|
@@ -419,6 +419,9 @@ export function createOpenApiDocument(providers, options = {}) {
|
|
|
419
419
|
service: jsonSchema.string({ description: "Provider service identifier." }),
|
|
420
420
|
authType: jsonSchema.string({ description: "Connection authentication type." }),
|
|
421
421
|
configured: jsonSchema.boolean({ description: "Whether the provider is connected." }),
|
|
422
|
+
oauthAuthorizationId: jsonSchema.string({
|
|
423
|
+
description: "Completed OAuth consent state. Omitted for legacy and non-OAuth connections.",
|
|
424
|
+
}),
|
|
422
425
|
virtual: jsonSchema.boolean({
|
|
423
426
|
description: "Whether the connection needs no stored secret.",
|
|
424
427
|
}),
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Directory to include in a host's Bun compile.assets. Its basename keeps connector assets namespaced. */
|
|
2
|
+
export declare function getConnectorAssetDirectory(): string;
|
|
3
|
+
/** Only Bun defines the `Bun` global; Node and workerd never do, so the read is safe everywhere. */
|
|
4
|
+
export declare function isStandaloneExecutable(): boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
/** Directory to include in a host's Bun compile.assets. Its basename keeps connector assets namespaced. */
|
|
4
|
+
export function getConnectorAssetDirectory() {
|
|
5
|
+
return isStandaloneExecutable()
|
|
6
|
+
? join(import.meta.dirname, "open-connector")
|
|
7
|
+
: fileURLToPath(new URL("../../assets/open-connector/", import.meta.url));
|
|
8
|
+
}
|
|
9
|
+
/** Only Bun defines the `Bun` global; Node and workerd never do, so the read is safe everywhere. */
|
|
10
|
+
export function isStandaloneExecutable() {
|
|
11
|
+
return globalThis.Bun?.isStandaloneExecutable === true;
|
|
12
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface ConnectorBuildOptions {
|
|
2
|
+
/** Omit to include all providers. An empty array includes none. */
|
|
3
|
+
providers?: readonly string[];
|
|
4
|
+
}
|
|
5
|
+
export interface ConnectorBuild {
|
|
6
|
+
/** Pass to Bun.build's compile.assets. */
|
|
7
|
+
assets: string[];
|
|
8
|
+
/** Pass to Bun.build alongside plugins. */
|
|
9
|
+
external: string[];
|
|
10
|
+
plugins: ConnectorBuildPlugin[];
|
|
11
|
+
/** Remove staged assets after the build, including when it fails. */
|
|
12
|
+
dispose(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
interface ConnectorBuildPlugin {
|
|
15
|
+
name: string;
|
|
16
|
+
setup(build: ConnectorBuildHooks): void;
|
|
17
|
+
}
|
|
18
|
+
interface ConnectorBuildHooks {
|
|
19
|
+
onLoad(options: {
|
|
20
|
+
filter: RegExp;
|
|
21
|
+
}, callback: (args: {
|
|
22
|
+
path: string;
|
|
23
|
+
}) => {
|
|
24
|
+
contents: string;
|
|
25
|
+
loader: "js";
|
|
26
|
+
} | undefined): unknown;
|
|
27
|
+
onEnd(callback: (result: {
|
|
28
|
+
success: boolean;
|
|
29
|
+
}) => void): unknown;
|
|
30
|
+
}
|
|
31
|
+
/** Prepare a headless Bun executable with only the requested provider code and catalog entries. */
|
|
32
|
+
export declare function getConnectorBuildOptions(options?: ConnectorBuildOptions): Promise<ConnectorBuild>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { access, cp, mkdir, mkdtemp, readdir, readFile, realpath, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { extname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { catalogIndexFileName, createCatalogIndex } from "../catalog-index.js";
|
|
6
|
+
import { assertProviderId } from "../core/provider-id.js";
|
|
7
|
+
import { getConnectorAssetDirectory } from "./connector-assets.js";
|
|
8
|
+
/** Prepare a headless Bun executable with only the requested provider code and catalog entries. */
|
|
9
|
+
export async function getConnectorBuildOptions(options = {}) {
|
|
10
|
+
const sourceAssets = getConnectorAssetDirectory();
|
|
11
|
+
const external = ["proxy-agent"];
|
|
12
|
+
if (options.providers === undefined) {
|
|
13
|
+
return { assets: [sourceAssets], external, plugins: [], dispose: () => Promise.resolve() };
|
|
14
|
+
}
|
|
15
|
+
const services = [...new Set(options.providers)].sort();
|
|
16
|
+
const catalogDir = join(sourceAssets, "catalog/apps");
|
|
17
|
+
const files = new Set(await readdir(catalogDir));
|
|
18
|
+
for (const service of services) {
|
|
19
|
+
assertProviderId(service);
|
|
20
|
+
if (!files.has(`${service}.json`))
|
|
21
|
+
throw new Error(`Unknown provider: ${service}`);
|
|
22
|
+
}
|
|
23
|
+
const directory = await mkdtemp(join(tmpdir(), "open-connector-build-"));
|
|
24
|
+
const dispose = () => rm(directory, { recursive: true, force: true });
|
|
25
|
+
try {
|
|
26
|
+
const assets = join(directory, "open-connector");
|
|
27
|
+
const apps = join(assets, "catalog/apps");
|
|
28
|
+
await mkdir(apps, { recursive: true });
|
|
29
|
+
const providerDir = fileURLToPath(new URL("../providers/", import.meta.url));
|
|
30
|
+
const extension = extname(import.meta.filename);
|
|
31
|
+
const registry = await realpath(join(providerDir, `registry.generated${extension}`));
|
|
32
|
+
const sources = [];
|
|
33
|
+
for (const service of services) {
|
|
34
|
+
await access(join(providerDir, service, `executors${extension}`));
|
|
35
|
+
const file = `${service}.json`;
|
|
36
|
+
const content = await readFile(join(catalogDir, file));
|
|
37
|
+
const provider = JSON.parse(content.toString());
|
|
38
|
+
if (provider.service !== service)
|
|
39
|
+
throw new Error(`Catalog service does not match ${file}`);
|
|
40
|
+
await writeFile(join(apps, file), content);
|
|
41
|
+
sources.push({ file, bytes: content.byteLength, provider });
|
|
42
|
+
}
|
|
43
|
+
// Bun embeds files, so preserve the directory that the runtime reads even with no providers.
|
|
44
|
+
if (!services.length)
|
|
45
|
+
await writeFile(join(apps, "empty"), "");
|
|
46
|
+
await writeFile(join(assets, "catalog", catalogIndexFileName), JSON.stringify(createCatalogIndex(sources)));
|
|
47
|
+
await cp(join(sourceAssets, "migrations"), join(assets, "migrations"), { recursive: true });
|
|
48
|
+
const contents = `export const executorModules = {\n${services
|
|
49
|
+
.map((service) => `${JSON.stringify(service)}: () => import(${JSON.stringify(`./${service}/executors${extension}`)}),`)
|
|
50
|
+
.join("\n")}\n};`;
|
|
51
|
+
const plugin = {
|
|
52
|
+
name: "open-connector-providers",
|
|
53
|
+
setup(build) {
|
|
54
|
+
let replaced = false;
|
|
55
|
+
build.onLoad({ filter: /[/\\]providers[/\\]registry\.generated\.[jt]s$/ }, ({ path }) => {
|
|
56
|
+
if (path !== registry)
|
|
57
|
+
return;
|
|
58
|
+
replaced = true;
|
|
59
|
+
return { contents, loader: "js" };
|
|
60
|
+
});
|
|
61
|
+
build.onEnd((result) => {
|
|
62
|
+
if (result.success && !replaced)
|
|
63
|
+
throw new Error("The build did not load Open Connector's executor registry.");
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
return { assets: [assets], external, plugins: [plugin], dispose };
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
await dispose();
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -79,8 +79,7 @@ export interface ConnectorRuntime {
|
|
|
79
79
|
/** Abort active requests, wait for their handlers, and close owned resources. Safe to call repeatedly. */
|
|
80
80
|
close(): Promise<void>;
|
|
81
81
|
}
|
|
82
|
-
|
|
83
|
-
export declare function getConnectorAssetDirectory(): string;
|
|
82
|
+
export { getConnectorAssetDirectory } from "./connector-assets.ts";
|
|
84
83
|
/** Create a headless runtime without opening a listener or installing process signal handlers. */
|
|
85
84
|
export declare function createConnectorRuntime(options: ConnectorRuntimeOptions): Promise<ConnectorRuntime>;
|
|
86
85
|
export type { RuntimeProviderSetup } from "./api/runtime-api.ts";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { mkdir } from "node:fs/promises";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
3
|
import { loadCatalog } from "../catalog-store.js";
|
|
5
4
|
import { ActionPolicyService } from "../core/action-policy.js";
|
|
6
5
|
import { setEgressTrustedHosts, setPrivateNetworkAccessAllowed } from "../core/request.js";
|
|
@@ -8,20 +7,15 @@ import { ProviderLoader } from "../providers/provider-loader.js";
|
|
|
8
7
|
import { executorModules } from "../providers/registry.generated.js";
|
|
9
8
|
import { createRuntimeJwtVerifier } from "./api/runtime-jwt.js";
|
|
10
9
|
import { createConnectApp } from "./connect-app.js";
|
|
10
|
+
import { getConnectorAssetDirectory } from "./connector-assets.js";
|
|
11
11
|
import { cleanupStagedTransitFiles, createNodeTransitFileUpload } from "./files/node-transit-file-upload.js";
|
|
12
12
|
import { TransitFileService } from "./files/transit-files.js";
|
|
13
13
|
import { createSecretCodec } from "./secrets/secret-codec.js";
|
|
14
|
-
import { isStandaloneExecutable } from "./server-assets.js";
|
|
15
14
|
import { createDirectoryMigrationSource } from "./storage/migration-source.js";
|
|
16
15
|
import { createNodeRuntimeDatabase } from "./storage/node-runtime-database.js";
|
|
17
16
|
import { DEFAULT_RUN_LIMIT } from "./storage/runtime-store.js";
|
|
18
17
|
let runtimeActive = false;
|
|
19
|
-
|
|
20
|
-
export function getConnectorAssetDirectory() {
|
|
21
|
-
return isStandaloneExecutable()
|
|
22
|
-
? join(import.meta.dirname, "open-connector")
|
|
23
|
-
: fileURLToPath(new URL("../../assets/open-connector/", import.meta.url));
|
|
24
|
-
}
|
|
18
|
+
export { getConnectorAssetDirectory } from "./connector-assets.js";
|
|
25
19
|
/** Create a headless runtime without opening a listener or installing process signal handlers. */
|
|
26
20
|
export async function createConnectorRuntime(options) {
|
|
27
21
|
if (runtimeActive)
|