import { readFile, writeFile } from 'node:fs/promises'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const usesendDir = path.join(__dirname, '..', 'node_modules', 'usesend-js'); const ensureReplacement = (content, searchValue, replaceValue, filePath) => { if (content.includes(replaceValue)) { return content; } if (!content.includes(searchValue)) { throw new Error(`Expected snippet not found in ${filePath}`); } return content.replace(searchValue, replaceValue); }; const patchFile = async (relativePath, replacements) => { const filePath = path.join(usesendDir, relativePath); let content = await readFile(filePath, 'utf8'); for (const [searchValue, replaceValue] of replacements) { content = ensureReplacement( content, searchValue, replaceValue, relativePath, ); } await writeFile(filePath, content); }; const patchUseSend = async () => { const packageJsonPath = path.join(usesendDir, 'package.json'); const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')); if (packageJson.version !== '1.6.3') { console.log( `Skipping UseSend patch for version ${packageJson.version ?? 'unknown'}.`, ); return; } const runtimeHelper = `function getNodeCrypto() { const builtinModuleLoader = globalThis.process?.getBuiltinModule; if (typeof builtinModuleLoader === "function") { const nodeCrypto = builtinModuleLoader("node:crypto"); if (nodeCrypto) { return nodeCrypto; } } throw new WebhookVerificationError( "UNSUPPORTED_RUNTIME", "Webhook verification requires a Node.js runtime with node:crypto support" ); } `; await patchFile('dist/index.mjs', [ ['import { createHmac, timingSafeEqual } from "crypto";\n', ''], [ 'function computeSignature(secret, timestamp, body) {\n', `${runtimeHelper}function computeSignature(secret, timestamp, body) {\n`, ], [ ' const hmac = createHmac("sha256", secret);\n', ' const { createHmac } = getNodeCrypto();\n const hmac = createHmac("sha256", secret);\n', ], [ 'function safeEqual(a, b) {\n', 'function safeEqual(a, b) {\n const { timingSafeEqual } = getNodeCrypto();\n', ], ]); await patchFile('dist/index.js', [ ['var import_crypto = require("crypto");\n', ''], [ 'function computeSignature(secret, timestamp, body) {\n', `${runtimeHelper}function computeSignature(secret, timestamp, body) {\n`, ], [ ' const hmac = (0, import_crypto.createHmac)("sha256", secret);\n', ' const { createHmac } = getNodeCrypto();\n const hmac = createHmac("sha256", secret);\n', ], [ 'function safeEqual(a, b) {\n', 'function safeEqual(a, b) {\n const { timingSafeEqual } = getNodeCrypto();\n', ], [ ' return (0, import_crypto.timingSafeEqual)(aBuf, bBuf);\n', ' return timingSafeEqual(aBuf, bBuf);\n', ], ]); console.log('Patched usesend-js 1.6.3 for Convex-compatible bundling.'); }; await patchUseSend();