Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Post articles and image-text content to WeChat Official Account via API or Chrome CDP, with markdown-to-WeChat HTML conversion.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/wechat-http.ts
1export interface WechatHttpInit {2method?: string;3headers?: Record<string, string>;4body?: string | Buffer;5}67export interface WechatHttpResponse {8status: number;9statusText: string;10headers: Record<string, string | string[] | undefined>;11buffer(): Promise<Buffer>;12text(): Promise<string>;13json<T = unknown>(): Promise<T>;14}1516export type WechatClient = (17url: string,18init?: WechatHttpInit,19) => Promise<WechatHttpResponse>;2021export interface MultipartFilePart {22name: string;23filename: string;24contentType: string;25data: Buffer;26}2728export interface MultipartBody {29contentType: string;30body: Buffer;31}3233export function buildMultipart(parts: MultipartFilePart[]): MultipartBody {34const boundary = `----WebKitFormBoundary${Date.now().toString(16)}${Math.random().toString(16).slice(2, 10)}`;35const chunks: Buffer[] = [];3637for (const part of parts) {38const header =39`--${boundary}\r\n` +40`Content-Disposition: form-data; name="${part.name}"; filename="${part.filename}"\r\n` +41`Content-Type: ${part.contentType}\r\n\r\n`;42chunks.push(Buffer.from(header, "utf-8"));43chunks.push(part.data);44chunks.push(Buffer.from("\r\n", "utf-8"));45}46chunks.push(Buffer.from(`--${boundary}--\r\n`, "utf-8"));4748return {49contentType: `multipart/form-data; boundary=${boundary}`,50body: Buffer.concat(chunks),51};52}5354function headersToRecord(headers: Headers): Record<string, string | string[] | undefined> {55const out: Record<string, string | string[] | undefined> = {};56headers.forEach((value, key) => {57const existing = out[key];58if (existing === undefined) {59out[key] = value;60} else if (Array.isArray(existing)) {61existing.push(value);62} else {63out[key] = [existing, value];64}65});66return out;67}6869export const wechatHttp: WechatClient = async (url, init = {}) => {70const method = init.method ?? (init.body !== undefined ? "POST" : "GET");71const headers: Record<string, string> = { ...(init.headers ?? {}) };7273let body: BodyInit | undefined;74if (init.body !== undefined) {75body = Buffer.isBuffer(init.body)76? new Uint8Array(init.body.buffer, init.body.byteOffset, init.body.byteLength)77: init.body;78}7980const res = await fetch(url, { method, headers, body });81const buf = Buffer.from(await res.arrayBuffer());8283return {84status: res.status,85statusText: res.statusText,86headers: headersToRecord(res.headers),87async buffer() {88return buf;89},90async text() {91return buf.toString("utf-8");92},93async json<T = unknown>() {94return JSON.parse(buf.toString("utf-8")) as T;95},96};97};98