@axiom-lattice/gateway 2.1.99 → 2.1.101
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/.turbo/turbo-build.log +16 -16
- package/CHANGELOG.md +23 -0
- package/dist/{WechatChannelAdapter-QQYOHZTL.mjs → WechatChannelAdapter-WSDKR4OA.mjs} +23 -17
- package/dist/WechatChannelAdapter-WSDKR4OA.mjs.map +1 -0
- package/dist/index.js +36 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/channels/wechat/WechatChannelAdapter.ts +3 -3
- package/src/channels/wechat/__tests__/context-store.test.ts +148 -0
- package/src/channels/wechat/context-store.ts +22 -15
- package/src/controllers/workspace.ts +16 -9
- package/dist/WechatChannelAdapter-QQYOHZTL.mjs.map +0 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @axiom-lattice/gateway@2.1.
|
|
2
|
+
> @axiom-lattice/gateway@2.1.101 build /home/runner/work/agentic/agentic/packages/gateway
|
|
3
3
|
> tsup src/index.ts --format cjs,esm --dts --clean --sourcemap
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -9,6 +9,17 @@
|
|
|
9
9
|
[34mCLI[39m Cleaning output folder
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
11
|
[34mESM[39m Build start
|
|
12
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m271.22 KB[39m
|
|
13
|
+
[32mESM[39m [1mdist/sender-PX32VSHB.mjs [22m[32m873.00 B[39m
|
|
14
|
+
[32mESM[39m [1mdist/WechatChannelAdapter-WSDKR4OA.mjs [22m[32m8.27 KB[39m
|
|
15
|
+
[32mESM[39m [1mdist/chunk-6CUQGDJI.mjs [22m[32m6.42 KB[39m
|
|
16
|
+
[32mESM[39m [1mdist/a2a-ERG5RMUW.mjs [22m[32m15.95 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m575.35 KB[39m
|
|
18
|
+
[32mESM[39m [1mdist/sender-PX32VSHB.mjs.map [22m[32m2.07 KB[39m
|
|
19
|
+
[32mESM[39m [1mdist/WechatChannelAdapter-WSDKR4OA.mjs.map [22m[32m16.28 KB[39m
|
|
20
|
+
[32mESM[39m [1mdist/chunk-6CUQGDJI.mjs.map [22m[32m14.04 KB[39m
|
|
21
|
+
[32mESM[39m [1mdist/a2a-ERG5RMUW.mjs.map [22m[32m32.14 KB[39m
|
|
22
|
+
[32mESM[39m ⚡️ Build success in 475ms
|
|
12
23
|
[warn] [33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1m"import.meta" is not available with the "cjs" output format and will be empty[0m [empty-import-meta]
|
|
13
24
|
|
|
14
25
|
src/index.ts:189:33:
|
|
@@ -18,21 +29,10 @@
|
|
|
18
29
|
You need to set the output format to "esm" for "import.meta" to work correctly.
|
|
19
30
|
|
|
20
31
|
|
|
21
|
-
[
|
|
22
|
-
[
|
|
23
|
-
[
|
|
24
|
-
[32mESM[39m [1mdist/chunk-6CUQGDJI.mjs [22m[32m6.42 KB[39m
|
|
25
|
-
[32mESM[39m [1mdist/a2a-ERG5RMUW.mjs [22m[32m15.95 KB[39m
|
|
26
|
-
[32mESM[39m [1mdist/index.mjs.map [22m[32m575.03 KB[39m
|
|
27
|
-
[32mESM[39m [1mdist/sender-PX32VSHB.mjs.map [22m[32m2.07 KB[39m
|
|
28
|
-
[32mESM[39m [1mdist/WechatChannelAdapter-QQYOHZTL.mjs.map [22m[32m15.71 KB[39m
|
|
29
|
-
[32mESM[39m [1mdist/chunk-6CUQGDJI.mjs.map [22m[32m14.04 KB[39m
|
|
30
|
-
[32mESM[39m [1mdist/a2a-ERG5RMUW.mjs.map [22m[32m32.14 KB[39m
|
|
31
|
-
[32mESM[39m ⚡️ Build success in 548ms
|
|
32
|
-
[32mCJS[39m [1mdist/index.js [22m[32m308.91 KB[39m
|
|
33
|
-
[32mCJS[39m [1mdist/index.js.map [22m[32m639.22 KB[39m
|
|
34
|
-
[32mCJS[39m ⚡️ Build success in 576ms
|
|
32
|
+
[32mCJS[39m [1mdist/index.js [22m[32m309.50 KB[39m
|
|
33
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m640.11 KB[39m
|
|
34
|
+
[32mCJS[39m ⚡️ Build success in 507ms
|
|
35
35
|
[34mDTS[39m Build start
|
|
36
|
-
[32mDTS[39m ⚡️ Build success in
|
|
36
|
+
[32mDTS[39m ⚡️ Build success in 19468ms
|
|
37
37
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m7.57 KB[39m
|
|
38
38
|
[32mDTS[39m [1mdist/index.d.mts [22m[32m7.57 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @axiom-lattice/gateway
|
|
2
2
|
|
|
3
|
+
## 2.1.101
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0552021: WeChat channel improvements:
|
|
8
|
+
- QR code setup: replace auto-polling with manual refresh button + 5-min countdown timer
|
|
9
|
+
- context-store: key by installationId::senderId to prevent cross-installation token collision
|
|
10
|
+
- 13cd999: fix sandbox
|
|
11
|
+
- Updated dependencies [13cd999]
|
|
12
|
+
- @axiom-lattice/core@2.1.89
|
|
13
|
+
- @axiom-lattice/agent-eval@2.1.83
|
|
14
|
+
- @axiom-lattice/pg-stores@1.0.80
|
|
15
|
+
|
|
16
|
+
## 2.1.100
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [44c570c]
|
|
21
|
+
- Updated dependencies [2b71973]
|
|
22
|
+
- @axiom-lattice/core@2.1.88
|
|
23
|
+
- @axiom-lattice/agent-eval@2.1.82
|
|
24
|
+
- @axiom-lattice/pg-stores@1.0.79
|
|
25
|
+
|
|
3
26
|
## 2.1.99
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
|
@@ -11,31 +11,37 @@ import { z } from "zod";
|
|
|
11
11
|
var TOKEN_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
12
12
|
var store = /* @__PURE__ */ new Map();
|
|
13
13
|
var timers = /* @__PURE__ */ new Map();
|
|
14
|
-
function
|
|
15
|
-
|
|
14
|
+
function makeKey(installationId, senderId) {
|
|
15
|
+
return `${installationId}::${senderId}`;
|
|
16
|
+
}
|
|
17
|
+
function getContextToken(installationId, senderId) {
|
|
18
|
+
const key = makeKey(installationId, senderId);
|
|
19
|
+
const entry = store.get(key);
|
|
16
20
|
if (!entry) return void 0;
|
|
17
21
|
if (Date.now() - entry.updatedAt > TOKEN_TTL_MS) {
|
|
18
|
-
deleteContextToken(senderId);
|
|
22
|
+
deleteContextToken(installationId, senderId);
|
|
19
23
|
return void 0;
|
|
20
24
|
}
|
|
21
25
|
return entry.token;
|
|
22
26
|
}
|
|
23
|
-
function setContextToken(senderId, token) {
|
|
24
|
-
const
|
|
27
|
+
function setContextToken(installationId, senderId, token) {
|
|
28
|
+
const key = makeKey(installationId, senderId);
|
|
29
|
+
const existingTimer = timers.get(key);
|
|
25
30
|
if (existingTimer) clearTimeout(existingTimer);
|
|
26
|
-
store.set(
|
|
31
|
+
store.set(key, { token, installationId, senderId, updatedAt: Date.now() });
|
|
27
32
|
const timer = setTimeout(() => {
|
|
28
|
-
store.delete(
|
|
29
|
-
timers.delete(
|
|
33
|
+
store.delete(key);
|
|
34
|
+
timers.delete(key);
|
|
30
35
|
}, TOKEN_TTL_MS);
|
|
31
|
-
timers.set(
|
|
36
|
+
timers.set(key, timer);
|
|
32
37
|
}
|
|
33
|
-
function deleteContextToken(senderId) {
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
function deleteContextToken(installationId, senderId) {
|
|
39
|
+
const key = makeKey(installationId, senderId);
|
|
40
|
+
store.delete(key);
|
|
41
|
+
const timer = timers.get(key);
|
|
36
42
|
if (timer) {
|
|
37
43
|
clearTimeout(timer);
|
|
38
|
-
timers.delete(
|
|
44
|
+
timers.delete(key);
|
|
39
45
|
}
|
|
40
46
|
}
|
|
41
47
|
|
|
@@ -81,7 +87,7 @@ var wechatChannelAdapter = {
|
|
|
81
87
|
const text = extractText(msg);
|
|
82
88
|
if (!text) return null;
|
|
83
89
|
if (msg.context_token) {
|
|
84
|
-
setContextToken(senderId, msg.context_token);
|
|
90
|
+
setContextToken(installation.id, senderId, msg.context_token);
|
|
85
91
|
}
|
|
86
92
|
return {
|
|
87
93
|
channel: "wechat",
|
|
@@ -107,13 +113,13 @@ var wechatChannelAdapter = {
|
|
|
107
113
|
},
|
|
108
114
|
async sendReply(replyTarget, message, installation) {
|
|
109
115
|
const senderId = replyTarget.rawTarget.senderId;
|
|
110
|
-
const contextToken = getContextToken(senderId);
|
|
116
|
+
const contextToken = getContextToken(installation.id, senderId);
|
|
111
117
|
if (!contextToken) {
|
|
112
118
|
logger.warn("WeChat context token expired, cannot send reply", {
|
|
113
119
|
installationId: installation.id,
|
|
114
120
|
senderId
|
|
115
121
|
});
|
|
116
|
-
deleteContextToken(senderId);
|
|
122
|
+
deleteContextToken(installation.id, senderId);
|
|
117
123
|
return;
|
|
118
124
|
}
|
|
119
125
|
const { botToken } = installation.config;
|
|
@@ -246,4 +252,4 @@ var wechatChannelAdapter = {
|
|
|
246
252
|
export {
|
|
247
253
|
wechatChannelAdapter
|
|
248
254
|
};
|
|
249
|
-
//# sourceMappingURL=WechatChannelAdapter-
|
|
255
|
+
//# sourceMappingURL=WechatChannelAdapter-WSDKR4OA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/channels/wechat/WechatChannelAdapter.ts","../src/channels/wechat/context-store.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type {\n ChannelAdapter,\n InboundMessage,\n OutboundMessage,\n ReplyTarget,\n ChannelInstallation,\n} from \"@axiom-lattice/protocols\";\nimport type { WechatChannelInstallationConfig } from \"@axiom-lattice/protocols\";\nimport { getUpdates, sendMessage } from \"./wechat-client\";\nimport { setContextToken, getContextToken, deleteContextToken } from \"./context-store\";\nimport { Logger } from \"../../logger/Logger\";\n\nconst logger = new Logger({ serviceName: \"lattice/gateway/wechat\" });\n\nconst wechatConfigSchema = z.object({\n botToken: z.string(),\n uin: z.string().optional(),\n});\n\nconst MAX_RECONNECT_DELAY_MS = 30_000;\nconst BASE_RECONNECT_DELAY_MS = 1_000;\nconst HEARTBEAT_INTERVAL_MS = 60_000;\nconst CHANNEL_VERSION = \"1.0.2\";\n\n// ─── Message type constants ───────────────────────────────────────────────\n\nconst MSG_TYPE_USER = 1;\nconst MSG_ITEM_TEXT = 1;\n\n// ─── Polling connection state ─────────────────────────────────────────────\n\ninterface PollingState {\n installationId: string;\n abortController: AbortController;\n lastActivity: number;\n heartbeatTimer: NodeJS.Timeout;\n}\n\nconst activeConnections = new Map<string, PollingState>();\n\n// ─── Message dedup ────────────────────────────────────────────────────────\n\nconst seenClientIds = new Set<string>();\n\nfunction addToDedup(clientId: string): boolean {\n if (!clientId || seenClientIds.has(clientId)) return false;\n seenClientIds.add(clientId);\n if (seenClientIds.size > 1000) {\n const first = seenClientIds.values().next().value;\n if (first !== undefined) seenClientIds.delete(first);\n }\n return true;\n}\n\n// ─── Text extraction from iLink message ───────────────────────────────────\n\nfunction extractText(msg: { item_list?: Array<{ type?: number; text_item?: { text?: string } }> }): string | null {\n if (!msg.item_list?.length) return null;\n for (const item of msg.item_list) {\n if (item.type === MSG_ITEM_TEXT && item.text_item?.text) {\n return item.text_item.text;\n }\n }\n return null;\n}\n\n// ─── Adapter ──────────────────────────────────────────────────────────────\n\nexport const wechatChannelAdapter: ChannelAdapter<WechatChannelInstallationConfig> = {\n channel: \"wechat\",\n\n configSchema: wechatConfigSchema,\n\n async receive(\n rawPayload: unknown,\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n ): Promise<InboundMessage | null> {\n const msg = rawPayload as {\n from_user_id?: string;\n client_id?: string;\n message_type?: number;\n item_list?: Array<{ type?: number; text_item?: { text?: string } }>;\n context_token?: string;\n };\n\n // Only process user messages (type 1), skip bot echoes (type 2)\n if (msg.message_type !== MSG_TYPE_USER) return null;\n\n const senderId = msg.from_user_id;\n if (!senderId) return null;\n\n const text = extractText(msg);\n if (!text) return null;\n\n // Cache context token for reply\n if (msg.context_token) {\n setContextToken(installation.id, senderId, msg.context_token);\n }\n\n return {\n channel: \"wechat\",\n channelInstallationId: installation.id,\n tenantId: installation.tenantId,\n sender: {\n id: senderId,\n displayName: senderId.split(\"@\")[0],\n },\n content: {\n text,\n },\n conversation: {\n id: senderId,\n type: \"direct\",\n },\n replyTarget: {\n adapterChannel: \"wechat\",\n channelInstallationId: installation.id,\n rawTarget: { senderId },\n },\n };\n },\n\n async sendReply(\n replyTarget: ReplyTarget,\n message: OutboundMessage,\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n ): Promise<void> {\n const senderId = replyTarget.rawTarget.senderId as string;\n const contextToken = getContextToken(installation.id, senderId);\n\n if (!contextToken) {\n logger.warn(\"WeChat context token expired, cannot send reply\", {\n installationId: installation.id,\n senderId,\n });\n deleteContextToken(installation.id, senderId);\n return;\n }\n\n const { botToken } = installation.config;\n await sendMessage(botToken, senderId, message.text, contextToken);\n },\n\n resolveThreadId(message: InboundMessage, binding: unknown): string {\n const date = new Date().toISOString().split(\"T\")[0];\n const agentId = (binding as { agentId: string }).agentId;\n return `wechat:dm:${message.sender.id}:${agentId}:${date}`;\n },\n\n async connect(\n installation: ChannelInstallation<WechatChannelInstallationConfig>,\n deps?: unknown,\n ): Promise<void> {\n const { id: installationId, tenantId, config } = installation;\n\n if (!config.botToken) {\n logger.warn(\"WeChat installation missing botToken, skipping\", { installationId });\n return;\n }\n\n if (activeConnections.has(installationId)) {\n logger.warn(\"WeChat polling already running for installation, skipping\", { installationId });\n return;\n }\n\n logger.info(\"WeChat polling starting\", { installationId, tenantId });\n\n const abortController = new AbortController();\n\n const heartbeatTimer = setInterval(() => {\n const state2 = activeConnections.get(installationId);\n if (!state2) {\n clearInterval(heartbeatTimer);\n return;\n }\n const elapsed = Date.now() - state2.lastActivity;\n if (elapsed > HEARTBEAT_INTERVAL_MS * 2) {\n logger.error(\"WeChat polling heartbeat lost — no activity\", {\n installationId,\n elapsedMs: elapsed,\n });\n state2.abortController.abort();\n }\n }, HEARTBEAT_INTERVAL_MS);\n\n const state: PollingState = {\n installationId,\n abortController,\n lastActivity: Date.now(),\n heartbeatTimer,\n };\n activeConnections.set(installationId, state);\n\n const router = (deps as { router?: { dispatch(msg: InboundMessage): Promise<unknown> } })?.router;\n\n let syncBuffer = \"\";\n let reconnectDelay = BASE_RECONNECT_DELAY_MS;\n\n const scheduleNextPoll = (): void => {\n poll().catch((err) => {\n logger.error(\"WeChat poll iteration crashed\", {\n installationId,\n error: err instanceof Error ? err.message : String(err),\n });\n const currentState = activeConnections.get(installationId);\n if (currentState && !currentState.abortController.signal.aborted) {\n setTimeout(scheduleNextPoll, reconnectDelay);\n }\n });\n };\n\n const poll = async (): Promise<void> => {\n const currentState = activeConnections.get(installationId);\n if (!currentState || currentState.abortController.signal.aborted) {\n logger.info(\"WeChat polling aborted\", { installationId });\n return;\n }\n\n try {\n const result = await getUpdates(\n config.botToken,\n syncBuffer,\n currentState.abortController.signal,\n );\n syncBuffer = result.syncBuffer;\n reconnectDelay = BASE_RECONNECT_DELAY_MS;\n currentState.lastActivity = Date.now();\n\n if (result.msgs.length > 0) {\n logger.info(\"WeChat poll received messages\", {\n installationId,\n count: result.msgs.length,\n });\n }\n\n for (const rawMsg of result.msgs) {\n // Only user messages, skip bot echoes and non-text\n if (rawMsg.message_type !== MSG_TYPE_USER) continue;\n\n const text = extractText(rawMsg);\n if (!text) continue;\n\n if (!addToDedup((rawMsg as { client_id?: string }).client_id ?? \"\")) continue;\n\n const inbound = await wechatChannelAdapter.receive(\n rawMsg,\n installation as ChannelInstallation<WechatChannelInstallationConfig>,\n );\n if (inbound && router) {\n const dispatchResult = await router.dispatch(inbound);\n if (!(dispatchResult as { success?: boolean }).success) {\n logger.warn(\"WeChat dispatch failed\", {\n installationId,\n error: (dispatchResult as { error?: { message?: string } }).error?.message,\n });\n }\n }\n }\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") {\n logger.info(\"WeChat poll aborted by signal\", { installationId });\n return;\n }\n\n logger.error(\"WeChat poll error\", {\n installationId,\n error: err instanceof Error ? err.message : String(err),\n });\n await new Promise((resolve) => setTimeout(resolve, reconnectDelay));\n reconnectDelay = Math.min(reconnectDelay * 2, MAX_RECONNECT_DELAY_MS);\n }\n\n scheduleNextPoll();\n };\n\n scheduleNextPoll();\n logger.info(\"WeChat polling started\", { installationId });\n },\n\n async disconnect(installationId: string): Promise<void> {\n const state = activeConnections.get(installationId);\n if (!state) {\n logger.warn(\"WeChat polling not running, nothing to disconnect\", { installationId });\n return;\n }\n\n logger.info(\"WeChat polling disconnecting\", { installationId });\n state.abortController.abort();\n clearInterval(state.heartbeatTimer);\n activeConnections.delete(installationId);\n logger.info(\"WeChat polling disconnected\", { installationId });\n },\n};\n","interface ContextTokenEntry {\n token: string;\n installationId: string;\n senderId: string;\n updatedAt: number;\n}\n\nconst TOKEN_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\nconst store = new Map<string, ContextTokenEntry>();\nconst timers = new Map<string, NodeJS.Timeout>();\n\nfunction makeKey(installationId: string, senderId: string): string {\n return `${installationId}::${senderId}`;\n}\n\nexport function getContextToken(installationId: string, senderId: string): string | undefined {\n const key = makeKey(installationId, senderId);\n const entry = store.get(key);\n if (!entry) return undefined;\n if (Date.now() - entry.updatedAt > TOKEN_TTL_MS) {\n deleteContextToken(installationId, senderId);\n return undefined;\n }\n return entry.token;\n}\n\nexport function setContextToken(installationId: string, senderId: string, token: string): void {\n const key = makeKey(installationId, senderId);\n\n const existingTimer = timers.get(key);\n if (existingTimer) clearTimeout(existingTimer);\n\n store.set(key, { token, installationId, senderId, updatedAt: Date.now() });\n\n const timer = setTimeout(() => {\n store.delete(key);\n timers.delete(key);\n }, TOKEN_TTL_MS);\n timers.set(key, timer);\n}\n\nexport function deleteContextToken(installationId: string, senderId: string): void {\n const key = makeKey(installationId, senderId);\n store.delete(key);\n const timer = timers.get(key);\n if (timer) {\n clearTimeout(timer);\n timers.delete(key);\n }\n}\n\nexport function getContextTokenStoreSize(): number {\n return store.size;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -311,31 +311,37 @@ var init_wechat_client = __esm({
|
|
|
311
311
|
});
|
|
312
312
|
|
|
313
313
|
// src/channels/wechat/context-store.ts
|
|
314
|
-
function
|
|
315
|
-
|
|
314
|
+
function makeKey(installationId, senderId) {
|
|
315
|
+
return `${installationId}::${senderId}`;
|
|
316
|
+
}
|
|
317
|
+
function getContextToken(installationId, senderId) {
|
|
318
|
+
const key = makeKey(installationId, senderId);
|
|
319
|
+
const entry = store.get(key);
|
|
316
320
|
if (!entry) return void 0;
|
|
317
321
|
if (Date.now() - entry.updatedAt > TOKEN_TTL_MS) {
|
|
318
|
-
deleteContextToken(senderId);
|
|
322
|
+
deleteContextToken(installationId, senderId);
|
|
319
323
|
return void 0;
|
|
320
324
|
}
|
|
321
325
|
return entry.token;
|
|
322
326
|
}
|
|
323
|
-
function setContextToken(senderId, token) {
|
|
324
|
-
const
|
|
327
|
+
function setContextToken(installationId, senderId, token) {
|
|
328
|
+
const key = makeKey(installationId, senderId);
|
|
329
|
+
const existingTimer = timers.get(key);
|
|
325
330
|
if (existingTimer) clearTimeout(existingTimer);
|
|
326
|
-
store.set(
|
|
331
|
+
store.set(key, { token, installationId, senderId, updatedAt: Date.now() });
|
|
327
332
|
const timer = setTimeout(() => {
|
|
328
|
-
store.delete(
|
|
329
|
-
timers.delete(
|
|
333
|
+
store.delete(key);
|
|
334
|
+
timers.delete(key);
|
|
330
335
|
}, TOKEN_TTL_MS);
|
|
331
|
-
timers.set(
|
|
336
|
+
timers.set(key, timer);
|
|
332
337
|
}
|
|
333
|
-
function deleteContextToken(senderId) {
|
|
334
|
-
|
|
335
|
-
|
|
338
|
+
function deleteContextToken(installationId, senderId) {
|
|
339
|
+
const key = makeKey(installationId, senderId);
|
|
340
|
+
store.delete(key);
|
|
341
|
+
const timer = timers.get(key);
|
|
336
342
|
if (timer) {
|
|
337
343
|
clearTimeout(timer);
|
|
338
|
-
timers.delete(
|
|
344
|
+
timers.delete(key);
|
|
339
345
|
}
|
|
340
346
|
}
|
|
341
347
|
var TOKEN_TTL_MS, store, timers;
|
|
@@ -402,7 +408,7 @@ var init_WechatChannelAdapter = __esm({
|
|
|
402
408
|
const text = extractText(msg);
|
|
403
409
|
if (!text) return null;
|
|
404
410
|
if (msg.context_token) {
|
|
405
|
-
setContextToken(senderId, msg.context_token);
|
|
411
|
+
setContextToken(installation.id, senderId, msg.context_token);
|
|
406
412
|
}
|
|
407
413
|
return {
|
|
408
414
|
channel: "wechat",
|
|
@@ -428,13 +434,13 @@ var init_WechatChannelAdapter = __esm({
|
|
|
428
434
|
},
|
|
429
435
|
async sendReply(replyTarget, message, installation) {
|
|
430
436
|
const senderId = replyTarget.rawTarget.senderId;
|
|
431
|
-
const contextToken = getContextToken(senderId);
|
|
437
|
+
const contextToken = getContextToken(installation.id, senderId);
|
|
432
438
|
if (!contextToken) {
|
|
433
439
|
logger4.warn("WeChat context token expired, cannot send reply", {
|
|
434
440
|
installationId: installation.id,
|
|
435
441
|
senderId
|
|
436
442
|
});
|
|
437
|
-
deleteContextToken(senderId);
|
|
443
|
+
deleteContextToken(installation.id, senderId);
|
|
438
444
|
return;
|
|
439
445
|
}
|
|
440
446
|
const { botToken } = installation.config;
|
|
@@ -4565,9 +4571,13 @@ var WorkspaceController = class {
|
|
|
4565
4571
|
const isBinary = this.isBinaryContentType(filename2);
|
|
4566
4572
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, resolvedPath);
|
|
4567
4573
|
let buf;
|
|
4568
|
-
if (volumeBackend
|
|
4569
|
-
|
|
4570
|
-
|
|
4574
|
+
if (volumeBackend) {
|
|
4575
|
+
if (isBinary && volumeBackend.readBinary) {
|
|
4576
|
+
buf = await volumeBackend.readBinary(resolvedPath);
|
|
4577
|
+
} else {
|
|
4578
|
+
const fileData = await volumeBackend.readRaw(resolvedPath);
|
|
4579
|
+
buf = Buffer.from(fileData.content.join("\n"), "utf-8");
|
|
4580
|
+
}
|
|
4571
4581
|
} else {
|
|
4572
4582
|
const sandbox = await sandboxManager.getSandboxFromConfig(volumeConfig);
|
|
4573
4583
|
buf = await sandbox.file.downloadFile({ file: resolvedPath });
|
|
@@ -4615,9 +4625,13 @@ var WorkspaceController = class {
|
|
|
4615
4625
|
const isBinary = this.isBinaryContentType(filename2);
|
|
4616
4626
|
const volumeBackend = await sandboxManager.getVolumeBackendForPath(volumeConfig, resolvedPath);
|
|
4617
4627
|
let buf;
|
|
4618
|
-
if (volumeBackend
|
|
4619
|
-
|
|
4620
|
-
|
|
4628
|
+
if (volumeBackend) {
|
|
4629
|
+
if (isBinary && volumeBackend.readBinary) {
|
|
4630
|
+
buf = await volumeBackend.readBinary(resolvedPath);
|
|
4631
|
+
} else {
|
|
4632
|
+
const fileData = await volumeBackend.readRaw(resolvedPath);
|
|
4633
|
+
buf = Buffer.from(fileData.content.join("\n"), "utf-8");
|
|
4634
|
+
}
|
|
4621
4635
|
} else {
|
|
4622
4636
|
const sandbox = await sandboxManager.getSandboxFromConfig(volumeConfig);
|
|
4623
4637
|
buf = await sandbox.file.downloadFile({ file: resolvedPath });
|