@nextclaw/channel-extension-weixin 0.1.11 → 0.1.12-beta.1
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/services/weixin-auth-capability.service.js +2 -2
- package/dist/services/weixin-auth-capability.service.js.map +1 -1
- package/dist/services/weixin-login.service.d.ts +3 -3
- package/dist/services/weixin-login.service.d.ts.map +1 -1
- package/dist/services/weixin-login.service.js +4 -4
- package/dist/services/weixin-login.service.js.map +1 -1
- package/package.json +4 -4
|
@@ -8,7 +8,7 @@ var WeixinAuthCapability = class {
|
|
|
8
8
|
this.loginService = deps.loginService ?? new WeixinLoginService();
|
|
9
9
|
}
|
|
10
10
|
start = async (request) => await this.loginService.start({
|
|
11
|
-
|
|
11
|
+
channelConfig: await this.readCurrentConfig(),
|
|
12
12
|
requestedAccountId: this.readString(request.accountId),
|
|
13
13
|
baseUrl: this.readString(request.baseUrl)
|
|
14
14
|
});
|
|
@@ -18,7 +18,7 @@ var WeixinAuthCapability = class {
|
|
|
18
18
|
return await this.loginService.poll({ sessionId });
|
|
19
19
|
};
|
|
20
20
|
login = async (request) => await this.loginService.login({
|
|
21
|
-
|
|
21
|
+
channelConfig: await this.readCurrentConfig(),
|
|
22
22
|
requestedAccountId: this.readString(request.accountId),
|
|
23
23
|
baseUrl: this.readString(request.baseUrl),
|
|
24
24
|
verbose: request.verbose === true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weixin-auth-capability.service.js","names":[],"sources":["../../src/services/weixin-auth-capability.service.ts"],"sourcesContent":["import type {\n ExtensionChannel,\n ExtensionCapabilityPayload,\n} from \"@nextclaw/extension-sdk\";\nimport { WeixinLoginService } from \"./weixin-login.service.js\";\n\ntype WeixinAuthCapabilityDeps = {\n channel: ExtensionChannel;\n loginService?: Pick<WeixinLoginService, \"start\" | \"poll\" | \"login\">;\n};\n\nexport class WeixinAuthCapability {\n private readonly channel: ExtensionChannel;\n private readonly loginService: Pick<WeixinLoginService, \"start\" | \"poll\" | \"login\">;\n\n constructor(deps: WeixinAuthCapabilityDeps) {\n this.channel = deps.channel;\n this.loginService = deps.loginService ?? new WeixinLoginService();\n }\n\n readonly start = async (\n request: ExtensionCapabilityPayload,\n ): Promise<unknown> =>\n await this.loginService.start({\n
|
|
1
|
+
{"version":3,"file":"weixin-auth-capability.service.js","names":[],"sources":["../../src/services/weixin-auth-capability.service.ts"],"sourcesContent":["import type {\n ExtensionChannel,\n ExtensionCapabilityPayload,\n} from \"@nextclaw/extension-sdk\";\nimport { WeixinLoginService } from \"./weixin-login.service.js\";\n\ntype WeixinAuthCapabilityDeps = {\n channel: ExtensionChannel;\n loginService?: Pick<WeixinLoginService, \"start\" | \"poll\" | \"login\">;\n};\n\nexport class WeixinAuthCapability {\n private readonly channel: ExtensionChannel;\n private readonly loginService: Pick<WeixinLoginService, \"start\" | \"poll\" | \"login\">;\n\n constructor(deps: WeixinAuthCapabilityDeps) {\n this.channel = deps.channel;\n this.loginService = deps.loginService ?? new WeixinLoginService();\n }\n\n readonly start = async (\n request: ExtensionCapabilityPayload,\n ): Promise<unknown> =>\n await this.loginService.start({\n channelConfig: await this.readCurrentConfig(),\n requestedAccountId: this.readString(request.accountId),\n baseUrl: this.readString(request.baseUrl),\n });\n\n readonly poll = async (\n request: ExtensionCapabilityPayload,\n ): Promise<unknown> => {\n const sessionId = this.readString(request.sessionId);\n if (!sessionId) {\n throw new Error(\"sessionId is required\");\n }\n return await this.loginService.poll({ sessionId });\n };\n\n readonly login = async (\n request: ExtensionCapabilityPayload,\n ): Promise<unknown> =>\n await this.loginService.login({\n channelConfig: await this.readCurrentConfig(),\n requestedAccountId: this.readString(request.accountId),\n baseUrl: this.readString(request.baseUrl),\n verbose: request.verbose === true,\n });\n\n private readonly readCurrentConfig = async (): Promise<Record<string, unknown>> => {\n const config = await this.channel.config.get();\n return config && typeof config === \"object\" && !Array.isArray(config)\n ? config as Record<string, unknown>\n : {};\n };\n\n private readonly readString = (value: unknown): string | null =>\n typeof value === \"string\" && value.trim() ? value.trim() : null;\n}\n"],"mappings":";;AAWA,IAAa,uBAAb,MAAkC;CAChC;CACA;CAEA,YAAY,MAAgC;AAC1C,OAAK,UAAU,KAAK;AACpB,OAAK,eAAe,KAAK,gBAAgB,IAAI,oBAAoB;;CAGnE,QAAiB,OACf,YAEA,MAAM,KAAK,aAAa,MAAM;EAC5B,eAAe,MAAM,KAAK,mBAAmB;EAC7C,oBAAoB,KAAK,WAAW,QAAQ,UAAU;EACtD,SAAS,KAAK,WAAW,QAAQ,QAAQ;EAC1C,CAAC;CAEJ,OAAgB,OACd,YACqB;EACrB,MAAM,YAAY,KAAK,WAAW,QAAQ,UAAU;AACpD,MAAI,CAAC,UACH,OAAM,IAAI,MAAM,wBAAwB;AAE1C,SAAO,MAAM,KAAK,aAAa,KAAK,EAAE,WAAW,CAAC;;CAGpD,QAAiB,OACf,YAEA,MAAM,KAAK,aAAa,MAAM;EAC5B,eAAe,MAAM,KAAK,mBAAmB;EAC7C,oBAAoB,KAAK,WAAW,QAAQ,UAAU;EACtD,SAAS,KAAK,WAAW,QAAQ,QAAQ;EACzC,SAAS,QAAQ,YAAY;EAC9B,CAAC;CAEJ,oBAAqC,YAA8C;EACjF,MAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,KAAK;AAC9C,SAAO,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,OAAO,GACjE,SACA,EAAE;;CAGR,cAA+B,UAC7B,OAAO,UAAU,YAAY,MAAM,MAAM,GAAG,MAAM,MAAM,GAAG"}
|
|
@@ -3,7 +3,7 @@ import { WeixinApiClient } from "./weixin-api.service.js";
|
|
|
3
3
|
|
|
4
4
|
//#region src/services/weixin-login.service.d.ts
|
|
5
5
|
type WeixinLoginParams = {
|
|
6
|
-
|
|
6
|
+
channelConfig?: Record<string, unknown>;
|
|
7
7
|
requestedAccountId?: string | null;
|
|
8
8
|
baseUrl?: string | null;
|
|
9
9
|
verbose?: boolean;
|
|
@@ -25,7 +25,7 @@ type WeixinAuthPollResult = {
|
|
|
25
25
|
nextPollMs?: number;
|
|
26
26
|
accountId?: string | null;
|
|
27
27
|
notes?: string[];
|
|
28
|
-
|
|
28
|
+
channelConfig?: Record<string, unknown>;
|
|
29
29
|
};
|
|
30
30
|
type WeixinLoginServiceDeps = {
|
|
31
31
|
api?: WeixinApiClient;
|
|
@@ -43,7 +43,7 @@ declare class WeixinLoginService {
|
|
|
43
43
|
sessionId: string;
|
|
44
44
|
}) => Promise<WeixinAuthPollResult | null>;
|
|
45
45
|
readonly login: (params: WeixinLoginParams) => Promise<{
|
|
46
|
-
|
|
46
|
+
channelConfig: Record<string, unknown>;
|
|
47
47
|
accountId?: string | null;
|
|
48
48
|
notes?: string[];
|
|
49
49
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weixin-login.service.d.ts","names":[],"sources":["../../src/services/weixin-login.service.ts"],"mappings":";;;;KAWY,iBAAA;EACV,
|
|
1
|
+
{"version":3,"file":"weixin-login.service.d.ts","names":[],"sources":["../../src/services/weixin-login.service.ts"],"mappings":";;;;KAWY,iBAAA;EACV,aAAA,GAAgB,MAAA;EAChB,kBAAA;EACA,OAAA;EACA,OAAA;AAAA;AAAA,KAGU,qBAAA;EACV,OAAA;EACA,IAAA;EACA,SAAA;EACA,MAAA;EACA,SAAA;EACA,SAAA;EACA,UAAA;EACA,IAAA;AAAA;AAAA,KAGU,oBAAA;EACV,OAAA;EACA,MAAA;EACA,OAAA;EACA,UAAA;EACA,SAAA;EACA,KAAA;EACA,aAAA,GAAgB,MAAA;AAAA;AAAA,KAWb,sBAAA;EACH,GAAA,GAAM,eAAA;EACN,KAAA,GAAQ,kBAAA;AAAA;AAAA,cAiCG,kBAAA;EAAA,iBACM,GAAA;EAAA,iBACA,KAAA;EAAA,iBACA,QAAA;cAEL,IAAA,GAAM,sBAAA;EAAA,SAKT,KAAA,GAAe,MAAA,EAAQ,iBAAA,KAAoB,OAAA,CAAQ,qBAAA;EAAA,SAkCnD,IAAA;IAAc;EAAA;IAAiB,SAAA;EAAA,MAAsB,OAAA,CAAQ,oBAAA;EAAA,SAuE7D,KAAA,GACP,MAAA,EAAQ,iBAAA,KACP,OAAA;IAAU,aAAA,EAAe,MAAA;IAAyB,SAAA;IAA2B,KAAA;EAAA;EAAA,iBAuC/D,YAAA;EAAA,iBAqDA,4BAAA;EAAA,iBAiCA,sBAAA;AAAA"}
|
|
@@ -32,7 +32,7 @@ var WeixinLoginService = class {
|
|
|
32
32
|
}
|
|
33
33
|
start = async (params) => {
|
|
34
34
|
this.cleanupExpiredSessions();
|
|
35
|
-
const currentConfig = normalizeWeixinChannelConfig(params.
|
|
35
|
+
const currentConfig = normalizeWeixinChannelConfig(params.channelConfig);
|
|
36
36
|
const baseUrl = resolveLoginBaseUrl(params, currentConfig);
|
|
37
37
|
const qrCode = await this.api.fetchQrCode({ baseUrl });
|
|
38
38
|
const qrCodeUrl = qrCode.qrcode_img_content?.trim();
|
|
@@ -93,7 +93,7 @@ var WeixinLoginService = class {
|
|
|
93
93
|
nextPollMs: 0,
|
|
94
94
|
accountId: result.accountId,
|
|
95
95
|
notes: result.notes,
|
|
96
|
-
|
|
96
|
+
channelConfig: result.channelConfig
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
if (normalizedStatus === "expired") {
|
|
@@ -132,7 +132,7 @@ var WeixinLoginService = class {
|
|
|
132
132
|
seenScanned = true;
|
|
133
133
|
}
|
|
134
134
|
if (status.status === "authorized") return {
|
|
135
|
-
|
|
135
|
+
channelConfig: status.channelConfig ?? {},
|
|
136
136
|
accountId: status.accountId,
|
|
137
137
|
notes: status.notes
|
|
138
138
|
};
|
|
@@ -173,7 +173,7 @@ var WeixinLoginService = class {
|
|
|
173
173
|
...replacementAccountIds.map((replacementAccountId) => `Replaced previous Weixin account: ${replacementAccountId}`),
|
|
174
174
|
...userId ? [`Authorized initial user: ${userId}`] : []
|
|
175
175
|
],
|
|
176
|
-
|
|
176
|
+
channelConfig: buildLoggedInWeixinChannelConfig({
|
|
177
177
|
config: session.currentConfig,
|
|
178
178
|
accountId,
|
|
179
179
|
baseUrl,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weixin-login.service.js","names":[],"sources":["../../src/services/weixin-login.service.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { FileWeixinAccountStore, type WeixinAccountStore } from \"../stores/weixin-account.store.js\";\nimport { HttpWeixinApiClient, type WeixinApiClient, type WeixinQrStatusResponse } from \"./weixin-api.service.js\";\nimport {\n buildLoggedInWeixinChannelConfig,\n DEFAULT_WEIXIN_BASE_URL,\n normalizeWeixinChannelConfig,\n WEIXIN_CHANNEL_ID,\n} from \"../utils/weixin-config.utils.js\";\nimport type { WeixinChannelConfig } from \"../types/weixin-extension.types.js\";\n\nexport type WeixinLoginParams = {\n pluginConfig?: Record<string, unknown>;\n requestedAccountId?: string | null;\n baseUrl?: string | null;\n verbose?: boolean;\n};\n\nexport type WeixinAuthStartResult = {\n channel: string;\n kind: \"qr_code\";\n sessionId: string;\n qrCode: string;\n qrCodeUrl: string;\n expiresAt: string;\n intervalMs: number;\n note?: string;\n};\n\nexport type WeixinAuthPollResult = {\n channel: string;\n status: \"pending\" | \"scanned\" | \"authorized\" | \"expired\" | \"error\";\n message?: string;\n nextPollMs?: number;\n accountId?: string | null;\n notes?: string[];\n pluginConfig?: Record<string, unknown>;\n};\n\ntype WeixinLoginSession = {\n currentConfig: WeixinChannelConfig;\n requestedAccountId?: string | null;\n baseUrl: string;\n qrCode: string;\n expiresAtMs: number;\n};\n\ntype WeixinLoginServiceDeps = {\n api?: WeixinApiClient;\n store?: WeixinAccountStore;\n};\n\nconst WEIXIN_LOGIN_TIMEOUT_MS = 8 * 60_000;\nconst WEIXIN_AUTH_POLL_INTERVAL_MS = 2_000;\nconst WEIXIN_AUTH_STATUS_TIMEOUT_MS = 5_000;\n\nasync function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));\n}\n\nfunction resolveLoginBaseUrl(params: WeixinLoginParams, currentConfig: WeixinChannelConfig): string {\n return params.baseUrl?.trim() || currentConfig.baseUrl || DEFAULT_WEIXIN_BASE_URL;\n}\n\nfunction normalizeQrStatus(status: string | undefined): \"pending\" | \"scanned\" | \"authorized\" | \"expired\" {\n const normalized = status?.trim().toLowerCase() ?? \"\";\n if (normalized === \"scaned\" || normalized === \"scanned\") {\n return \"scanned\";\n }\n if (normalized === \"confirmed\" || normalized === \"authorized\" || normalized === \"success\") {\n return \"authorized\";\n }\n if (normalized === \"expired\" || normalized === \"timeout\") {\n return \"expired\";\n }\n return \"pending\";\n}\n\nfunction hasAuthorizedCredentials(status: WeixinQrStatusResponse): boolean {\n return Boolean(status.bot_token?.trim() && status.ilink_bot_id?.trim());\n}\n\nexport class WeixinLoginService {\n private readonly api: WeixinApiClient;\n private readonly store: WeixinAccountStore;\n private readonly sessions = new Map<string, WeixinLoginSession>();\n\n constructor(deps: WeixinLoginServiceDeps = {}) {\n this.api = deps.api ?? new HttpWeixinApiClient();\n this.store = deps.store ?? new FileWeixinAccountStore();\n }\n\n readonly start = async (params: WeixinLoginParams): Promise<WeixinAuthStartResult> => {\n this.cleanupExpiredSessions();\n const currentConfig = normalizeWeixinChannelConfig(params.pluginConfig);\n const baseUrl = resolveLoginBaseUrl(params, currentConfig);\n const qrCode = await this.api.fetchQrCode({ baseUrl });\n const qrCodeUrl = qrCode.qrcode_img_content?.trim();\n const qrCodeValue = qrCode.qrcode?.trim();\n\n if (!qrCodeUrl || !qrCodeValue) {\n throw new Error(\"weixin login failed: QR code is unavailable\");\n }\n\n const sessionId = randomUUID();\n const expiresAtMs = Date.now() + WEIXIN_LOGIN_TIMEOUT_MS;\n this.sessions.set(sessionId, {\n currentConfig,\n requestedAccountId: params.requestedAccountId,\n baseUrl,\n qrCode: qrCodeValue,\n expiresAtMs,\n });\n\n return {\n channel: WEIXIN_CHANNEL_ID,\n kind: \"qr_code\",\n sessionId,\n qrCode: qrCodeValue,\n qrCodeUrl,\n expiresAt: new Date(expiresAtMs).toISOString(),\n intervalMs: WEIXIN_AUTH_POLL_INTERVAL_MS,\n note: \"请使用微信扫码,并在手机上确认登录。\",\n };\n };\n\n readonly poll = async ({ sessionId }: { sessionId: string }): Promise<WeixinAuthPollResult | null> => {\n this.cleanupExpiredSessions();\n const session = this.sessions.get(sessionId);\n if (!session) {\n return null;\n }\n if (session.expiresAtMs <= Date.now()) {\n this.sessions.delete(sessionId);\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"expired\",\n message: \"二维码已过期,请重新扫码。\",\n };\n }\n\n try {\n const status = await this.api.fetchQrStatus({\n baseUrl: session.baseUrl,\n qrcode: session.qrCode,\n timeoutMs: WEIXIN_AUTH_STATUS_TIMEOUT_MS,\n });\n const normalizedStatus = hasAuthorizedCredentials(status)\n ? \"authorized\"\n : normalizeQrStatus(status.status);\n\n if (normalizedStatus === \"scanned\") {\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"scanned\",\n message: \"二维码已扫码,请在微信中确认登录。\",\n nextPollMs: WEIXIN_AUTH_POLL_INTERVAL_MS,\n };\n }\n\n if (normalizedStatus === \"authorized\") {\n const result = this.confirmLogin(session, status);\n this.sessions.delete(sessionId);\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"authorized\",\n message: \"微信已连接。\",\n nextPollMs: 0,\n accountId: result.accountId,\n notes: result.notes,\n pluginConfig: result.pluginConfig,\n };\n }\n\n if (normalizedStatus === \"expired\") {\n this.sessions.delete(sessionId);\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"expired\",\n message: \"二维码已过期,请重新扫码。\",\n };\n }\n\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"pending\",\n nextPollMs: WEIXIN_AUTH_POLL_INTERVAL_MS,\n };\n } catch (error) {\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"error\",\n message: error instanceof Error ? error.message : String(error),\n };\n }\n };\n\n readonly login = async (\n params: WeixinLoginParams,\n ): Promise<{ pluginConfig: Record<string, unknown>; accountId?: string | null; notes?: string[] }> => {\n const started = await this.start(params);\n console.log(\"使用微信扫描以下二维码链接完成连接:\");\n console.log(started.qrCodeUrl);\n console.log(\"\");\n console.log(\"等待扫码确认...\");\n\n let seenScanned = false;\n while (Date.now() < new Date(started.expiresAt).getTime()) {\n const status = await this.poll({ sessionId: started.sessionId });\n if (!status) {\n throw new Error(\"weixin login failed: auth session not found\");\n }\n if (status.status === \"scanned\" && !seenScanned) {\n console.log(status.message ?? \"二维码已扫码,请在微信中确认登录。\");\n seenScanned = true;\n }\n if (status.status === \"authorized\") {\n return {\n pluginConfig: status.pluginConfig ?? {},\n accountId: status.accountId,\n notes: status.notes,\n };\n }\n if (status.status === \"expired\") {\n throw new Error(status.message ?? \"weixin login failed: QR code expired, please retry\");\n }\n if (status.status === \"error\") {\n throw new Error(status.message ?? \"weixin login failed\");\n }\n if (params.verbose) {\n process.stdout.write(\".\");\n }\n await sleep(status.nextPollMs ?? WEIXIN_AUTH_POLL_INTERVAL_MS);\n }\n\n throw new Error(\"weixin login timed out\");\n };\n\n private readonly confirmLogin = (\n session: WeixinLoginSession,\n status: WeixinQrStatusResponse,\n ): { pluginConfig: Record<string, unknown>; accountId: string; notes: string[] } => {\n const token = status.bot_token?.trim();\n const accountId = status.ilink_bot_id?.trim() || session.requestedAccountId?.trim();\n const baseUrl = status.baseurl?.trim() || session.baseUrl;\n const userId = status.ilink_user_id?.trim() || undefined;\n\n if (!token || !accountId) {\n throw new Error(\"weixin login failed: missing bot token or account id\");\n }\n\n const replacementAccountIds = this.resolveReplacementAccountIds({\n currentConfig: session.currentConfig,\n requestedAccountId: session.requestedAccountId,\n accountId,\n userId,\n });\n for (const replacementAccountId of replacementAccountIds) {\n this.store.deleteAccount(replacementAccountId);\n this.store.deleteCursor(replacementAccountId);\n }\n\n this.store.saveAccount({\n accountId,\n token,\n baseUrl,\n userId,\n savedAt: new Date().toISOString(),\n });\n\n const notes = [\n ...(session.requestedAccountId?.trim() && session.requestedAccountId.trim() !== accountId\n ? [`Weixin account resolved to ${accountId}.`]\n : []),\n ...replacementAccountIds.map((replacementAccountId) => `Replaced previous Weixin account: ${replacementAccountId}`),\n ...(userId ? [`Authorized initial user: ${userId}`] : []),\n ];\n\n return {\n accountId,\n notes,\n pluginConfig: buildLoggedInWeixinChannelConfig({\n config: session.currentConfig,\n accountId,\n baseUrl,\n allowUserId: userId,\n replaceAccountIds: replacementAccountIds,\n }) as Record<string, unknown>,\n };\n };\n\n private readonly resolveReplacementAccountIds = (params: {\n currentConfig: WeixinChannelConfig;\n requestedAccountId?: string | null;\n accountId: string;\n userId?: string;\n }): string[] => {\n const { accountId, currentConfig, requestedAccountId: requestedAccountIdRaw, userId } = params;\n const replacementIds = new Set<string>();\n const requestedAccountId = requestedAccountIdRaw?.trim();\n const defaultAccountId = currentConfig.defaultAccountId?.trim();\n\n if (requestedAccountId && requestedAccountId !== accountId) {\n replacementIds.add(requestedAccountId);\n } else if (!requestedAccountId && defaultAccountId && defaultAccountId !== accountId) {\n replacementIds.add(defaultAccountId);\n }\n\n if (userId) {\n for (const [candidateAccountId, accountConfig] of Object.entries(currentConfig.accounts ?? {})) {\n if (candidateAccountId !== accountId && accountConfig.allowFrom?.includes(userId)) {\n replacementIds.add(candidateAccountId);\n }\n }\n for (const candidateAccountId of this.store.listAccountIds()) {\n if (candidateAccountId !== accountId && this.store.loadAccount(candidateAccountId)?.userId === userId) {\n replacementIds.add(candidateAccountId);\n }\n }\n }\n\n return [...replacementIds];\n };\n\n private readonly cleanupExpiredSessions = (now = Date.now()): void => {\n for (const [sessionId, session] of this.sessions.entries()) {\n if (session.expiresAtMs <= now) {\n this.sessions.delete(sessionId);\n }\n }\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"weixin-login.service.js","names":[],"sources":["../../src/services/weixin-login.service.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { FileWeixinAccountStore, type WeixinAccountStore } from \"../stores/weixin-account.store.js\";\nimport { HttpWeixinApiClient, type WeixinApiClient, type WeixinQrStatusResponse } from \"./weixin-api.service.js\";\nimport {\n buildLoggedInWeixinChannelConfig,\n DEFAULT_WEIXIN_BASE_URL,\n normalizeWeixinChannelConfig,\n WEIXIN_CHANNEL_ID,\n} from \"../utils/weixin-config.utils.js\";\nimport type { WeixinChannelConfig } from \"../types/weixin-extension.types.js\";\n\nexport type WeixinLoginParams = {\n channelConfig?: Record<string, unknown>;\n requestedAccountId?: string | null;\n baseUrl?: string | null;\n verbose?: boolean;\n};\n\nexport type WeixinAuthStartResult = {\n channel: string;\n kind: \"qr_code\";\n sessionId: string;\n qrCode: string;\n qrCodeUrl: string;\n expiresAt: string;\n intervalMs: number;\n note?: string;\n};\n\nexport type WeixinAuthPollResult = {\n channel: string;\n status: \"pending\" | \"scanned\" | \"authorized\" | \"expired\" | \"error\";\n message?: string;\n nextPollMs?: number;\n accountId?: string | null;\n notes?: string[];\n channelConfig?: Record<string, unknown>;\n};\n\ntype WeixinLoginSession = {\n currentConfig: WeixinChannelConfig;\n requestedAccountId?: string | null;\n baseUrl: string;\n qrCode: string;\n expiresAtMs: number;\n};\n\ntype WeixinLoginServiceDeps = {\n api?: WeixinApiClient;\n store?: WeixinAccountStore;\n};\n\nconst WEIXIN_LOGIN_TIMEOUT_MS = 8 * 60_000;\nconst WEIXIN_AUTH_POLL_INTERVAL_MS = 2_000;\nconst WEIXIN_AUTH_STATUS_TIMEOUT_MS = 5_000;\n\nasync function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));\n}\n\nfunction resolveLoginBaseUrl(params: WeixinLoginParams, currentConfig: WeixinChannelConfig): string {\n return params.baseUrl?.trim() || currentConfig.baseUrl || DEFAULT_WEIXIN_BASE_URL;\n}\n\nfunction normalizeQrStatus(status: string | undefined): \"pending\" | \"scanned\" | \"authorized\" | \"expired\" {\n const normalized = status?.trim().toLowerCase() ?? \"\";\n if (normalized === \"scaned\" || normalized === \"scanned\") {\n return \"scanned\";\n }\n if (normalized === \"confirmed\" || normalized === \"authorized\" || normalized === \"success\") {\n return \"authorized\";\n }\n if (normalized === \"expired\" || normalized === \"timeout\") {\n return \"expired\";\n }\n return \"pending\";\n}\n\nfunction hasAuthorizedCredentials(status: WeixinQrStatusResponse): boolean {\n return Boolean(status.bot_token?.trim() && status.ilink_bot_id?.trim());\n}\n\nexport class WeixinLoginService {\n private readonly api: WeixinApiClient;\n private readonly store: WeixinAccountStore;\n private readonly sessions = new Map<string, WeixinLoginSession>();\n\n constructor(deps: WeixinLoginServiceDeps = {}) {\n this.api = deps.api ?? new HttpWeixinApiClient();\n this.store = deps.store ?? new FileWeixinAccountStore();\n }\n\n readonly start = async (params: WeixinLoginParams): Promise<WeixinAuthStartResult> => {\n this.cleanupExpiredSessions();\n const currentConfig = normalizeWeixinChannelConfig(params.channelConfig);\n const baseUrl = resolveLoginBaseUrl(params, currentConfig);\n const qrCode = await this.api.fetchQrCode({ baseUrl });\n const qrCodeUrl = qrCode.qrcode_img_content?.trim();\n const qrCodeValue = qrCode.qrcode?.trim();\n\n if (!qrCodeUrl || !qrCodeValue) {\n throw new Error(\"weixin login failed: QR code is unavailable\");\n }\n\n const sessionId = randomUUID();\n const expiresAtMs = Date.now() + WEIXIN_LOGIN_TIMEOUT_MS;\n this.sessions.set(sessionId, {\n currentConfig,\n requestedAccountId: params.requestedAccountId,\n baseUrl,\n qrCode: qrCodeValue,\n expiresAtMs,\n });\n\n return {\n channel: WEIXIN_CHANNEL_ID,\n kind: \"qr_code\",\n sessionId,\n qrCode: qrCodeValue,\n qrCodeUrl,\n expiresAt: new Date(expiresAtMs).toISOString(),\n intervalMs: WEIXIN_AUTH_POLL_INTERVAL_MS,\n note: \"请使用微信扫码,并在手机上确认登录。\",\n };\n };\n\n readonly poll = async ({ sessionId }: { sessionId: string }): Promise<WeixinAuthPollResult | null> => {\n this.cleanupExpiredSessions();\n const session = this.sessions.get(sessionId);\n if (!session) {\n return null;\n }\n if (session.expiresAtMs <= Date.now()) {\n this.sessions.delete(sessionId);\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"expired\",\n message: \"二维码已过期,请重新扫码。\",\n };\n }\n\n try {\n const status = await this.api.fetchQrStatus({\n baseUrl: session.baseUrl,\n qrcode: session.qrCode,\n timeoutMs: WEIXIN_AUTH_STATUS_TIMEOUT_MS,\n });\n const normalizedStatus = hasAuthorizedCredentials(status)\n ? \"authorized\"\n : normalizeQrStatus(status.status);\n\n if (normalizedStatus === \"scanned\") {\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"scanned\",\n message: \"二维码已扫码,请在微信中确认登录。\",\n nextPollMs: WEIXIN_AUTH_POLL_INTERVAL_MS,\n };\n }\n\n if (normalizedStatus === \"authorized\") {\n const result = this.confirmLogin(session, status);\n this.sessions.delete(sessionId);\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"authorized\",\n message: \"微信已连接。\",\n nextPollMs: 0,\n accountId: result.accountId,\n notes: result.notes,\n channelConfig: result.channelConfig,\n };\n }\n\n if (normalizedStatus === \"expired\") {\n this.sessions.delete(sessionId);\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"expired\",\n message: \"二维码已过期,请重新扫码。\",\n };\n }\n\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"pending\",\n nextPollMs: WEIXIN_AUTH_POLL_INTERVAL_MS,\n };\n } catch (error) {\n return {\n channel: WEIXIN_CHANNEL_ID,\n status: \"error\",\n message: error instanceof Error ? error.message : String(error),\n };\n }\n };\n\n readonly login = async (\n params: WeixinLoginParams,\n ): Promise<{ channelConfig: Record<string, unknown>; accountId?: string | null; notes?: string[] }> => {\n const started = await this.start(params);\n console.log(\"使用微信扫描以下二维码链接完成连接:\");\n console.log(started.qrCodeUrl);\n console.log(\"\");\n console.log(\"等待扫码确认...\");\n\n let seenScanned = false;\n while (Date.now() < new Date(started.expiresAt).getTime()) {\n const status = await this.poll({ sessionId: started.sessionId });\n if (!status) {\n throw new Error(\"weixin login failed: auth session not found\");\n }\n if (status.status === \"scanned\" && !seenScanned) {\n console.log(status.message ?? \"二维码已扫码,请在微信中确认登录。\");\n seenScanned = true;\n }\n if (status.status === \"authorized\") {\n return {\n channelConfig: status.channelConfig ?? {},\n accountId: status.accountId,\n notes: status.notes,\n };\n }\n if (status.status === \"expired\") {\n throw new Error(status.message ?? \"weixin login failed: QR code expired, please retry\");\n }\n if (status.status === \"error\") {\n throw new Error(status.message ?? \"weixin login failed\");\n }\n if (params.verbose) {\n process.stdout.write(\".\");\n }\n await sleep(status.nextPollMs ?? WEIXIN_AUTH_POLL_INTERVAL_MS);\n }\n\n throw new Error(\"weixin login timed out\");\n };\n\n private readonly confirmLogin = (\n session: WeixinLoginSession,\n status: WeixinQrStatusResponse,\n ): { channelConfig: Record<string, unknown>; accountId: string; notes: string[] } => {\n const token = status.bot_token?.trim();\n const accountId = status.ilink_bot_id?.trim() || session.requestedAccountId?.trim();\n const baseUrl = status.baseurl?.trim() || session.baseUrl;\n const userId = status.ilink_user_id?.trim() || undefined;\n\n if (!token || !accountId) {\n throw new Error(\"weixin login failed: missing bot token or account id\");\n }\n\n const replacementAccountIds = this.resolveReplacementAccountIds({\n currentConfig: session.currentConfig,\n requestedAccountId: session.requestedAccountId,\n accountId,\n userId,\n });\n for (const replacementAccountId of replacementAccountIds) {\n this.store.deleteAccount(replacementAccountId);\n this.store.deleteCursor(replacementAccountId);\n }\n\n this.store.saveAccount({\n accountId,\n token,\n baseUrl,\n userId,\n savedAt: new Date().toISOString(),\n });\n\n const notes = [\n ...(session.requestedAccountId?.trim() && session.requestedAccountId.trim() !== accountId\n ? [`Weixin account resolved to ${accountId}.`]\n : []),\n ...replacementAccountIds.map((replacementAccountId) => `Replaced previous Weixin account: ${replacementAccountId}`),\n ...(userId ? [`Authorized initial user: ${userId}`] : []),\n ];\n\n return {\n accountId,\n notes,\n channelConfig: buildLoggedInWeixinChannelConfig({\n config: session.currentConfig,\n accountId,\n baseUrl,\n allowUserId: userId,\n replaceAccountIds: replacementAccountIds,\n }) as Record<string, unknown>,\n };\n };\n\n private readonly resolveReplacementAccountIds = (params: {\n currentConfig: WeixinChannelConfig;\n requestedAccountId?: string | null;\n accountId: string;\n userId?: string;\n }): string[] => {\n const { accountId, currentConfig, requestedAccountId: requestedAccountIdRaw, userId } = params;\n const replacementIds = new Set<string>();\n const requestedAccountId = requestedAccountIdRaw?.trim();\n const defaultAccountId = currentConfig.defaultAccountId?.trim();\n\n if (requestedAccountId && requestedAccountId !== accountId) {\n replacementIds.add(requestedAccountId);\n } else if (!requestedAccountId && defaultAccountId && defaultAccountId !== accountId) {\n replacementIds.add(defaultAccountId);\n }\n\n if (userId) {\n for (const [candidateAccountId, accountConfig] of Object.entries(currentConfig.accounts ?? {})) {\n if (candidateAccountId !== accountId && accountConfig.allowFrom?.includes(userId)) {\n replacementIds.add(candidateAccountId);\n }\n }\n for (const candidateAccountId of this.store.listAccountIds()) {\n if (candidateAccountId !== accountId && this.store.loadAccount(candidateAccountId)?.userId === userId) {\n replacementIds.add(candidateAccountId);\n }\n }\n }\n\n return [...replacementIds];\n };\n\n private readonly cleanupExpiredSessions = (now = Date.now()): void => {\n for (const [sessionId, session] of this.sessions.entries()) {\n if (session.expiresAtMs <= now) {\n this.sessions.delete(sessionId);\n }\n }\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/channel-extension-weixin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12-beta.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "NextClaw Weixin channel extension process.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@nextclaw/extension-sdk": "0.1.
|
|
22
|
-
"@nextclaw/ncp": "0.5.
|
|
23
|
-
"@nextclaw/ncp-toolkit": "0.5.
|
|
21
|
+
"@nextclaw/extension-sdk": "0.1.12-beta.1",
|
|
22
|
+
"@nextclaw/ncp": "0.5.18-beta.1",
|
|
23
|
+
"@nextclaw/ncp-toolkit": "0.5.23-beta.1"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "^20.17.6",
|